playcademy 0.13.19 → 0.13.20

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/utils.js CHANGED
@@ -87,7 +87,8 @@ async function loadFile(filename, options = {}) {
87
87
  required = false,
88
88
  searchUp = false,
89
89
  maxLevels = 3,
90
- parseJson = false
90
+ parseJson = false,
91
+ stripComments = false
91
92
  } = options;
92
93
  let fileResult;
93
94
  if (searchUp) {
@@ -116,8 +117,11 @@ async function loadFile(filename, options = {}) {
116
117
  return null;
117
118
  }
118
119
  try {
119
- const content = await readFile(fileResult.path, "utf-8");
120
+ let content = await readFile(fileResult.path, "utf-8");
120
121
  if (parseJson) {
122
+ if (stripComments) {
123
+ content = stripJsonComments(content);
124
+ }
121
125
  return JSON.parse(content);
122
126
  }
123
127
  return content;
@@ -182,6 +186,11 @@ function getCurrentDirectoryName(fallback = "unknown-directory") {
182
186
  function getFileExtension(path2) {
183
187
  return path2.split(".").pop()?.toLowerCase();
184
188
  }
189
+ function stripJsonComments(jsonc) {
190
+ let result = jsonc.replace(/\/\*[\s\S]*?\*\//g, "");
191
+ result = result.replace(/\/\/.*/g, "");
192
+ return result;
193
+ }
185
194
  async function loadModule(filename, options = {}) {
186
195
  const { cwd = process.cwd(), required = false, searchUp = false, maxLevels = 3 } = options;
187
196
  let fileResult;
@@ -285,104 +294,230 @@ var init_file_loader = __esm({
285
294
  }
286
295
  });
287
296
 
288
- // src/lib/config/loader.ts
289
- init_file_loader();
290
- import { dirname as dirname2, resolve as resolve2 } from "path";
291
-
292
297
  // src/constants/api.ts
293
- var DEFAULT_API_ROUTES_DIRECTORY = "server/api";
298
+ var DEFAULT_API_ROUTES_DIRECTORY;
299
+ var init_api = __esm({
300
+ "src/constants/api.ts"() {
301
+ "use strict";
302
+ DEFAULT_API_ROUTES_DIRECTORY = "server/api";
303
+ }
304
+ });
305
+
306
+ // src/constants/config.ts
307
+ var ENV_FILES, TSCONFIG_FILES;
308
+ var init_config = __esm({
309
+ "src/constants/config.ts"() {
310
+ "use strict";
311
+ ENV_FILES = [
312
+ ".env",
313
+ // Loaded first
314
+ ".env.development",
315
+ // Overrides .env
316
+ ".env.local"
317
+ // Overrides all (highest priority)
318
+ ];
319
+ TSCONFIG_FILES = [
320
+ "tsconfig.app.json",
321
+ // Modern tooling (try first)
322
+ "tsconfig.json"
323
+ // Standard (fallback)
324
+ ];
325
+ }
326
+ });
327
+
328
+ // src/constants/database.ts
329
+ var init_database = __esm({
330
+ "src/constants/database.ts"() {
331
+ "use strict";
332
+ }
333
+ });
334
+
335
+ // src/constants/http-server.ts
336
+ var init_http_server = __esm({
337
+ "src/constants/http-server.ts"() {
338
+ "use strict";
339
+ }
340
+ });
294
341
 
295
342
  // src/constants/paths.ts
296
343
  import { join } from "path";
297
- var WORKSPACE_NAME = ".playcademy";
298
- var CLI_DIRECTORIES = {
299
- /** Root directory for CLI artifacts in workspace */
300
- WORKSPACE: WORKSPACE_NAME,
301
- /** Database directory within workspace */
302
- DATABASE: join(WORKSPACE_NAME, "db"),
303
- /** KV storage directory within workspace */
304
- KV: join(WORKSPACE_NAME, "kv"),
305
- /** Bucket storage directory within workspace */
306
- BUCKET: join(WORKSPACE_NAME, "bucket")
307
- };
344
+ var WORKSPACE_NAME, CLI_DIRECTORIES;
345
+ var init_paths = __esm({
346
+ "src/constants/paths.ts"() {
347
+ "use strict";
348
+ WORKSPACE_NAME = ".playcademy";
349
+ CLI_DIRECTORIES = {
350
+ /** Root directory for CLI artifacts in workspace */
351
+ WORKSPACE: WORKSPACE_NAME,
352
+ /** Database directory within workspace */
353
+ DATABASE: join(WORKSPACE_NAME, "db"),
354
+ /** KV storage directory within workspace */
355
+ KV: join(WORKSPACE_NAME, "kv"),
356
+ /** Bucket storage directory within workspace */
357
+ BUCKET: join(WORKSPACE_NAME, "bucket")
358
+ };
359
+ }
360
+ });
308
361
 
309
362
  // src/constants/ports.ts
310
- var DEFAULT_PORTS = {
311
- /** Sandbox server (mock platform API) */
312
- SANDBOX: 4321,
313
- /** Backend dev server (game backend with HMR) */
314
- BACKEND: 8788
315
- };
363
+ var DEFAULT_PORTS;
364
+ var init_ports = __esm({
365
+ "src/constants/ports.ts"() {
366
+ "use strict";
367
+ DEFAULT_PORTS = {
368
+ /** Sandbox server (mock platform API) */
369
+ SANDBOX: 4321,
370
+ /** Backend dev server (game backend with HMR) */
371
+ BACKEND: 8788
372
+ };
373
+ }
374
+ });
316
375
 
317
376
  // src/constants/timeback.ts
318
- var CONFIG_FILE_NAMES = [
319
- "playcademy.config.js",
320
- "playcademy.config.json",
321
- "playcademy.config.mjs"
322
- ];
377
+ var CONFIG_FILE_NAMES;
378
+ var init_timeback = __esm({
379
+ "src/constants/timeback.ts"() {
380
+ "use strict";
381
+ CONFIG_FILE_NAMES = [
382
+ "playcademy.config.js",
383
+ "playcademy.config.json",
384
+ "playcademy.config.mjs"
385
+ ];
386
+ }
387
+ });
388
+
389
+ // ../constants/src/auth.ts
390
+ var init_auth = __esm({
391
+ "../constants/src/auth.ts"() {
392
+ "use strict";
393
+ }
394
+ });
395
+
396
+ // ../constants/src/domains.ts
397
+ var init_domains = __esm({
398
+ "../constants/src/domains.ts"() {
399
+ "use strict";
400
+ }
401
+ });
402
+
403
+ // ../constants/src/env-vars.ts
404
+ var init_env_vars = __esm({
405
+ "../constants/src/env-vars.ts"() {
406
+ "use strict";
407
+ }
408
+ });
323
409
 
324
410
  // ../constants/src/overworld.ts
325
- var ITEM_SLUGS = {
326
- /** Primary platform currency */
327
- PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
328
- /** Experience points currency */
329
- PLAYCADEMY_XP: "PLAYCADEMY_XP",
330
- /** Core platform badges */
331
- FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
332
- EARLY_ADOPTER_BADGE: "EARLY_ADOPTER_BADGE",
333
- FIRST_GAME_BADGE: "FIRST_GAME_BADGE",
334
- /** Example items */
335
- COMMON_SWORD: "COMMON_SWORD",
336
- SMALL_HEALTH_POTION: "SMALL_HEALTH_POTION",
337
- SMALL_BACKPACK: "SMALL_BACKPACK",
338
- /** Placeable items */
339
- LAVA_LAMP: "LAVA_LAMP",
340
- BOOMBOX: "BOOMBOX",
341
- CABIN_BED: "CABIN_BED"
342
- };
343
- var CURRENCIES = {
344
- /** Primary platform currency slug */
345
- PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
346
- /** Experience points slug */
347
- XP: ITEM_SLUGS.PLAYCADEMY_XP
348
- };
349
- var BADGES = {
350
- FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
351
- EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
352
- FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
353
- };
354
- var CORE_GAME_UUIDS = {
355
- /** Internal playground game for development and testing */
356
- PLAYGROUND: "00000000-0000-0000-0000-000000000001"
357
- };
411
+ var ITEM_SLUGS, CURRENCIES, BADGES, CORE_GAME_UUIDS;
412
+ var init_overworld = __esm({
413
+ "../constants/src/overworld.ts"() {
414
+ "use strict";
415
+ ITEM_SLUGS = {
416
+ /** Primary platform currency */
417
+ PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
418
+ /** Experience points currency */
419
+ PLAYCADEMY_XP: "PLAYCADEMY_XP",
420
+ /** Core platform badges */
421
+ FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
422
+ EARLY_ADOPTER_BADGE: "EARLY_ADOPTER_BADGE",
423
+ FIRST_GAME_BADGE: "FIRST_GAME_BADGE",
424
+ /** Example items */
425
+ COMMON_SWORD: "COMMON_SWORD",
426
+ SMALL_HEALTH_POTION: "SMALL_HEALTH_POTION",
427
+ SMALL_BACKPACK: "SMALL_BACKPACK",
428
+ /** Placeable items */
429
+ LAVA_LAMP: "LAVA_LAMP",
430
+ BOOMBOX: "BOOMBOX",
431
+ CABIN_BED: "CABIN_BED"
432
+ };
433
+ CURRENCIES = {
434
+ /** Primary platform currency slug */
435
+ PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
436
+ /** Experience points slug */
437
+ XP: ITEM_SLUGS.PLAYCADEMY_XP
438
+ };
439
+ BADGES = {
440
+ FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
441
+ EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
442
+ FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
443
+ };
444
+ CORE_GAME_UUIDS = {
445
+ /** Internal playground game for development and testing */
446
+ PLAYGROUND: "00000000-0000-0000-0000-000000000001"
447
+ };
448
+ }
449
+ });
450
+
451
+ // ../constants/src/system.ts
452
+ var init_system = __esm({
453
+ "../constants/src/system.ts"() {
454
+ "use strict";
455
+ }
456
+ });
457
+
458
+ // ../constants/src/timeback.ts
459
+ var init_timeback2 = __esm({
460
+ "../constants/src/timeback.ts"() {
461
+ "use strict";
462
+ }
463
+ });
464
+
465
+ // ../constants/src/workers.ts
466
+ var init_workers = __esm({
467
+ "../constants/src/workers.ts"() {
468
+ "use strict";
469
+ }
470
+ });
471
+
472
+ // ../constants/src/index.ts
473
+ var init_src = __esm({
474
+ "../constants/src/index.ts"() {
475
+ "use strict";
476
+ init_auth();
477
+ init_domains();
478
+ init_env_vars();
479
+ init_overworld();
480
+ init_system();
481
+ init_timeback2();
482
+ init_workers();
483
+ }
484
+ });
485
+
486
+ // src/constants/urls.ts
487
+ var init_urls = __esm({
488
+ "src/constants/urls.ts"() {
489
+ "use strict";
490
+ init_src();
491
+ }
492
+ });
358
493
 
359
494
  // src/constants/index.ts
360
- var CLOUDFLARE_COMPATIBILITY_DATE = "2024-01-01";
495
+ var CLOUDFLARE_COMPATIBILITY_DATE;
496
+ var init_constants = __esm({
497
+ "src/constants/index.ts"() {
498
+ "use strict";
499
+ init_api();
500
+ init_config();
501
+ init_database();
502
+ init_http_server();
503
+ init_paths();
504
+ init_ports();
505
+ init_timeback();
506
+ init_urls();
507
+ CLOUDFLARE_COMPATIBILITY_DATE = "2024-01-01";
508
+ }
509
+ });
361
510
 
362
- // src/lib/config/loader.ts
363
- var ConfigError = class extends Error {
364
- constructor(message, field, suggestion) {
365
- super(message);
366
- this.field = field;
367
- this.suggestion = suggestion;
368
- this.name = "ConfigError";
369
- }
370
- /**
371
- * Format a user-friendly error message with the field and suggestion
372
- */
373
- toString() {
374
- let msg = `Configuration Error: ${this.message}`;
375
- if (this.field) {
376
- msg += `
377
- Field: ${this.field}`;
378
- }
379
- if (this.suggestion) {
380
- msg += `
381
- Suggestion: ${this.suggestion}`;
382
- }
383
- return msg;
511
+ // src/constants.ts
512
+ var init_constants2 = __esm({
513
+ "src/constants.ts"() {
514
+ "use strict";
515
+ init_constants();
384
516
  }
385
- };
517
+ });
518
+
519
+ // src/lib/config/loader.ts
520
+ import { dirname as dirname2, resolve as resolve2 } from "path";
386
521
  async function findConfigPath(configPath) {
387
522
  const { findFile: findFile2 } = await Promise.resolve().then(() => (init_file_loader(), file_loader_exports));
388
523
  if (configPath) {
@@ -565,89 +700,37 @@ function processConfigVariables(config) {
565
700
  };
566
701
  return processValue(processed);
567
702
  }
568
-
569
- // src/lib/dev/server.ts
570
- import { mkdir as mkdir2 } from "fs/promises";
571
- import { join as join9 } from "path";
572
- import { Log, LogLevel, Miniflare } from "miniflare";
573
-
574
- // ../utils/src/port.ts
575
- import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "node:fs";
576
- import { createServer } from "node:net";
577
- import { homedir } from "node:os";
578
- import { join as join2 } from "node:path";
579
- async function isPortAvailableOnHost(port, host) {
580
- return new Promise((resolve4) => {
581
- const server = createServer();
582
- server.once("error", () => {
583
- resolve4(false);
584
- });
585
- server.once("listening", () => {
586
- server.close();
587
- resolve4(true);
588
- });
589
- server.listen(port, host);
590
- });
591
- }
592
- async function findAvailablePort(startPort = 4321) {
593
- const [localhostAvailable, ipv4AllAvailable, ipv6AllAvailable] = await Promise.all([
594
- isPortAvailableOnHost(startPort, "127.0.0.1"),
595
- isPortAvailableOnHost(startPort, "0.0.0.0"),
596
- isPortAvailableOnHost(startPort, "::")
597
- ]);
598
- if (localhostAvailable && ipv4AllAvailable && ipv6AllAvailable) {
599
- return startPort;
600
- }
601
- return findAvailablePort(startPort + 1);
602
- }
603
- function getRegistryPath() {
604
- const home = homedir();
605
- const dir = join2(home, ".playcademy");
606
- if (!existsSync2(dir)) {
607
- mkdirSync(dir, { recursive: true });
608
- }
609
- return join2(dir, ".proc");
610
- }
611
- function readRegistry() {
612
- const registryPath = getRegistryPath();
613
- if (!existsSync2(registryPath)) {
614
- return {};
615
- }
616
- try {
617
- const content = readFileSync(registryPath, "utf-8");
618
- return JSON.parse(content);
619
- } catch {
620
- return {};
621
- }
622
- }
623
- function writeRegistry(registry) {
624
- const registryPath = getRegistryPath();
625
- writeFileSync(registryPath, JSON.stringify(registry, null, 2), "utf-8");
626
- }
627
- function getServerKey(type, port) {
628
- return `${type}-${port}`;
629
- }
630
- function writeServerInfo(type, info) {
631
- const registry = readRegistry();
632
- const key = getServerKey(type, info.port);
633
- registry[key] = info;
634
- writeRegistry(registry);
635
- }
636
- function readServerInfo(type, projectRoot) {
637
- const registry = readRegistry();
638
- const servers = Object.entries(registry).filter(([key]) => key.startsWith(`${type}-`)).map(([, info]) => info);
639
- if (servers.length === 0) {
640
- return null;
641
- }
642
- if (projectRoot) {
643
- const match = servers.find((s) => s.projectRoot === projectRoot);
644
- return match || null;
703
+ var ConfigError;
704
+ var init_loader = __esm({
705
+ "src/lib/config/loader.ts"() {
706
+ "use strict";
707
+ init_file_loader();
708
+ init_constants2();
709
+ ConfigError = class extends Error {
710
+ constructor(message, field, suggestion) {
711
+ super(message);
712
+ this.field = field;
713
+ this.suggestion = suggestion;
714
+ this.name = "ConfigError";
715
+ }
716
+ /**
717
+ * Format a user-friendly error message with the field and suggestion
718
+ */
719
+ toString() {
720
+ let msg = `Configuration Error: ${this.message}`;
721
+ if (this.field) {
722
+ msg += `
723
+ Field: ${this.field}`;
724
+ }
725
+ if (this.suggestion) {
726
+ msg += `
727
+ Suggestion: ${this.suggestion}`;
728
+ }
729
+ return msg;
730
+ }
731
+ };
645
732
  }
646
- return servers[0] || null;
647
- }
648
-
649
- // src/lib/core/client.ts
650
- import { PlaycademyClient } from "@playcademy/sdk";
733
+ });
651
734
 
652
735
  // ../utils/src/package-manager.ts
653
736
  import { execSync } from "child_process";
@@ -701,16 +784,29 @@ function getInstallCommand(pm) {
701
784
  return "npm install";
702
785
  }
703
786
  }
787
+ var init_package_manager = __esm({
788
+ "../utils/src/package-manager.ts"() {
789
+ "use strict";
790
+ }
791
+ });
704
792
 
705
793
  // src/lib/core/context.ts
706
- var context = {};
707
794
  function getWorkspace() {
708
795
  return context.workspace || process.cwd();
709
796
  }
797
+ var context;
798
+ var init_context = __esm({
799
+ "src/lib/core/context.ts"() {
800
+ "use strict";
801
+ init_package_manager();
802
+ context = {};
803
+ }
804
+ });
710
805
 
711
806
  // src/lib/core/logger.ts
712
807
  import {
713
808
  blue,
809
+ blueBright,
714
810
  bold,
715
811
  cyan,
716
812
  dim,
@@ -723,8 +819,10 @@ import {
723
819
  } from "colorette";
724
820
  import { colorize } from "json-colorizer";
725
821
  function customTransform(text) {
726
- const highlightCode = (text2) => text2.replace(/`([^`]+)`/g, (_, code) => greenBright(code));
727
- return highlightCode(text);
822
+ let result = text;
823
+ result = result.replace(/`([^`]+)`/g, (_, code) => greenBright(code));
824
+ result = result.replace(/<([^>]+)>/g, (_, path2) => blueBright(path2));
825
+ return result;
728
826
  }
729
827
  function formatTable(data, title) {
730
828
  if (data.length === 0) return;
@@ -757,159 +855,195 @@ function formatTable(data, title) {
757
855
  });
758
856
  console.log(bottomBorder);
759
857
  }
760
- var logger = {
761
- table: (data, title) => {
762
- formatTable(data, title);
763
- },
764
- /**
765
- * Info message - general information
766
- */
767
- info: (message, indent = 0) => {
768
- const spaces = " ".repeat(indent);
769
- console.log(`${spaces}${blue("\u2139")} ${bold(customTransform(message))}`);
770
- },
771
- /**
772
- * Admonition - highlighted note/tip/warning box (Docusaurus-style)
773
- */
774
- admonition: (type, title, lines, indent = 0) => {
775
- const spaces = " ".repeat(indent);
776
- const configs = {
777
- note: { color: green },
778
- tip: { color: cyan },
779
- info: { color: blue },
780
- warning: { color: yellow }
781
- };
782
- const { color } = configs[type];
783
- console.log(`${spaces}${color("\u250C\u2500")} ${bold(color(title.toUpperCase()))}`);
784
- if (lines && lines.length > 0) {
785
- lines.forEach((line) => {
786
- console.log(`${spaces}${color("\u2502")} ${customTransform(line)}`);
787
- });
788
- }
789
- console.log(`${spaces}${color("\u2514\u2500")}`);
790
- },
791
- /**
792
- * Dim message - less important information
793
- */
794
- dim: (message, indent = 0) => {
795
- const spaces = " ".repeat(indent);
796
- console.log(`${spaces}${dim(customTransform(message))}`);
797
- },
798
- /**
799
- * Success message - operation completed successfully
800
- */
801
- success: (message, indent = 0) => {
802
- const spaces = " ".repeat(indent);
803
- console.log(`${spaces}${green("\u2714")} ${bold(customTransform(message))}`);
804
- },
805
- remark: (message, indent = 0) => {
806
- const spaces = " ".repeat(indent);
807
- console.log(`${spaces}${bold(yellowBright("\u2726"))} ${bold(customTransform(message))}`);
808
- },
809
- /**
810
- * Error message - operation failed
811
- */
812
- error: (message, indent = 0) => {
813
- const spaces = " ".repeat(indent);
814
- console.error(`${spaces}${red("\u2716")} ${customTransform(message)}`);
815
- },
816
- bold: (message, indent = 0) => {
817
- const spaces = " ".repeat(indent);
818
- console.log(`${spaces}${bold(customTransform(message))}`);
819
- },
820
- /**
821
- * Warning message - something to be aware of
822
- */
823
- warn: (message, indent = 0) => {
824
- const spaces = " ".repeat(indent);
825
- console.warn(`${spaces}${yellow("\u26A0")} ${bold(customTransform(message))}`);
826
- },
827
- /**
828
- * Debug message - only shown when DEBUG env var is set
829
- */
830
- debug: (message, indent = 0) => {
831
- const spaces = " ".repeat(indent);
832
- if (process.env.DEBUG) {
833
- console.log(gray("[DEBUG]"), `${spaces}${message}`);
834
- }
835
- },
836
- /**
837
- * Step message - shows progress through a process
838
- */
839
- step: (step, total, message, indent = 0) => {
840
- const spaces = " ".repeat(indent);
841
- console.log(spaces + cyan(`[${step}/${total}]`), customTransform(message));
842
- },
843
- /**
844
- * Highlighted message - draws attention
845
- */
846
- highlight: (message, indent = 0) => {
847
- const spaces = " ".repeat(indent);
848
- console.log(bold(`${spaces}${cyan(customTransform(message))}`));
849
- },
850
- /**
851
- * Aside message - for side information
852
- */
853
- aside: (message, indent = 0) => {
854
- const spaces = " ".repeat(indent);
855
- console.log(`${spaces}${bold(customTransform(message))}`);
856
- },
857
- /**
858
- * Data display - for structured data output
859
- */
860
- data: (label, value, indent = 0) => {
861
- const spaces = " ".repeat(indent);
862
- if (value !== void 0) {
863
- console.log(`${spaces}${dim(label + ":")} ${bold(value)}`);
864
- } else {
865
- console.log(`${spaces}${dim(label)}`);
866
- }
867
- },
868
- /**
869
- * JSON output - pretty-printed JSON
870
- */
871
- json: (data, indent = 0) => {
872
- const spaces = " ".repeat(indent);
873
- const jsonString = colorize(JSON.stringify(data, null, 2));
874
- jsonString.split("\n").forEach((line) => {
875
- console.log(`${spaces}${line}`);
876
- });
877
- },
878
- /**
879
- * New line
880
- */
881
- newLine: () => {
882
- console.log();
883
- },
884
- /**
885
- * Raw output - no formatting, useful for ASCII art or pre-formatted text
886
- */
887
- raw: (text, indent = 0) => {
888
- const spaces = " ".repeat(indent);
889
- console.log(`${spaces}${text}`);
890
- },
891
- /**
892
- * Display a configuration error with helpful suggestions
893
- */
894
- configError: (error, indent = 0) => {
895
- const spaces = " ".repeat(indent);
896
- const isConfigError = error && typeof error === "object" && "name" in error && error.name === "ConfigError";
897
- if (isConfigError && "message" in error && "field" in error && "suggestion" in error) {
898
- const configErr = error;
899
- console.error(`${spaces}${red("\u2716")} ${bold(configErr.message)}`);
900
- if (configErr.field) {
901
- console.error(`${spaces} ${dim("Field:")} ${configErr.field}`);
902
- }
903
- if (configErr.suggestion) {
904
- console.error(`${spaces} ${dim("Fix:")} ${configErr.suggestion}`);
858
+ var logger;
859
+ var init_logger = __esm({
860
+ "src/lib/core/logger.ts"() {
861
+ "use strict";
862
+ logger = {
863
+ table: (data, title) => {
864
+ formatTable(data, title);
865
+ },
866
+ /**
867
+ * Info message - general information
868
+ */
869
+ info: (message, indent = 0) => {
870
+ const spaces = " ".repeat(indent);
871
+ console.log(`${spaces}${blue("\u2139")} ${bold(customTransform(message))}`);
872
+ },
873
+ /**
874
+ * Admonition - highlighted note/tip/warning box (Docusaurus-style)
875
+ */
876
+ admonition: (type, title, lines, indent = 0) => {
877
+ const spaces = " ".repeat(indent);
878
+ const configs = {
879
+ note: { color: green },
880
+ tip: { color: cyan },
881
+ info: { color: blue },
882
+ warning: { color: yellow }
883
+ };
884
+ const { color } = configs[type];
885
+ console.log(`${spaces}${color("\u250C\u2500")} ${bold(color(title.toUpperCase()))}`);
886
+ if (lines && lines.length > 0) {
887
+ lines.forEach((line) => {
888
+ console.log(`${spaces}${color("\u2502")} ${customTransform(line)}`);
889
+ });
890
+ }
891
+ console.log(`${spaces}${color("\u2514\u2500")}`);
892
+ },
893
+ /**
894
+ * Dim message - less important information
895
+ */
896
+ dim: (message, indent = 0) => {
897
+ const spaces = " ".repeat(indent);
898
+ console.log(`${spaces}${dim(customTransform(message))}`);
899
+ },
900
+ /**
901
+ * Success message - operation completed successfully
902
+ */
903
+ success: (message, indent = 0) => {
904
+ const spaces = " ".repeat(indent);
905
+ console.log(`${spaces}${green("\u2714")} ${bold(customTransform(message))}`);
906
+ },
907
+ remark: (message, indent = 0) => {
908
+ const spaces = " ".repeat(indent);
909
+ console.log(`${spaces}${bold(yellowBright("\u2726"))} ${bold(customTransform(message))}`);
910
+ },
911
+ /**
912
+ * Error message - operation failed
913
+ */
914
+ error: (message, indent = 0) => {
915
+ const spaces = " ".repeat(indent);
916
+ console.error(`${spaces}${red("\u2716")} ${customTransform(message)}`);
917
+ },
918
+ bold: (message, indent = 0) => {
919
+ const spaces = " ".repeat(indent);
920
+ console.log(`${spaces}${bold(customTransform(message))}`);
921
+ },
922
+ /**
923
+ * Warning message - something to be aware of
924
+ */
925
+ warn: (message, indent = 0) => {
926
+ const spaces = " ".repeat(indent);
927
+ console.warn(`${spaces}${yellow("\u26A0")} ${bold(customTransform(message))}`);
928
+ },
929
+ /**
930
+ * Debug message - only shown when DEBUG env var is set
931
+ */
932
+ debug: (message, indent = 0) => {
933
+ const spaces = " ".repeat(indent);
934
+ if (process.env.DEBUG) {
935
+ console.log(gray("[DEBUG]"), `${spaces}${message}`);
936
+ }
937
+ },
938
+ /**
939
+ * Step message - shows progress through a process
940
+ */
941
+ step: (step, total, message, indent = 0) => {
942
+ const spaces = " ".repeat(indent);
943
+ console.log(spaces + cyan(`[${step}/${total}]`), customTransform(message));
944
+ },
945
+ /**
946
+ * Highlighted message - draws attention
947
+ */
948
+ highlight: (message, indent = 0) => {
949
+ const spaces = " ".repeat(indent);
950
+ console.log(bold(`${spaces}${cyan(customTransform(message))}`));
951
+ },
952
+ /**
953
+ * Aside message - for side information
954
+ */
955
+ aside: (message, indent = 0) => {
956
+ const spaces = " ".repeat(indent);
957
+ console.log(`${spaces}${bold(customTransform(message))}`);
958
+ },
959
+ /**
960
+ * Data display - for structured data output
961
+ */
962
+ data: (label, value, indent = 0) => {
963
+ const spaces = " ".repeat(indent);
964
+ if (value !== void 0) {
965
+ console.log(`${spaces}${dim(label + ":")} ${bold(value)}`);
966
+ } else {
967
+ console.log(`${spaces}${dim(label)}`);
968
+ }
969
+ },
970
+ /**
971
+ * JSON output - pretty-printed JSON
972
+ */
973
+ json: (data, indent = 0) => {
974
+ const spaces = " ".repeat(indent);
975
+ const jsonString = colorize(JSON.stringify(data, null, 2));
976
+ jsonString.split("\n").forEach((line) => {
977
+ console.log(`${spaces}${line}`);
978
+ });
979
+ },
980
+ /**
981
+ * New line
982
+ */
983
+ newLine: () => {
984
+ console.log();
985
+ },
986
+ /**
987
+ * Raw output - no formatting, useful for ASCII art or pre-formatted text
988
+ */
989
+ raw: (text, indent = 0) => {
990
+ const spaces = " ".repeat(indent);
991
+ console.log(`${spaces}${text}`);
992
+ },
993
+ /**
994
+ * Display a configuration error with helpful suggestions
995
+ */
996
+ configError: (error, indent = 0) => {
997
+ const spaces = " ".repeat(indent);
998
+ const isConfigError = error && typeof error === "object" && "name" in error && error.name === "ConfigError";
999
+ if (isConfigError && "message" in error && "field" in error && "suggestion" in error) {
1000
+ const configErr = error;
1001
+ console.error(`${spaces}${red("\u2716")} ${bold(configErr.message)}`);
1002
+ if (configErr.field) {
1003
+ console.error(`${spaces} ${dim("Field:")} ${configErr.field}`);
1004
+ }
1005
+ if (configErr.suggestion) {
1006
+ console.error(`${spaces} ${dim("Fix:")} ${configErr.suggestion}`);
1007
+ }
1008
+ } else if (error instanceof Error) {
1009
+ console.error(`${spaces}${red("\u2716")} ${bold(error.message)}`);
1010
+ } else {
1011
+ console.error(`${spaces}${red("\u2716")} ${bold(String(error))}`);
1012
+ }
905
1013
  }
906
- } else if (error instanceof Error) {
907
- console.error(`${spaces}${red("\u2716")} ${bold(error.message)}`);
908
- } else {
909
- console.error(`${spaces}${red("\u2716")} ${bold(String(error))}`);
910
- }
1014
+ };
911
1015
  }
912
- };
1016
+ });
1017
+
1018
+ // src/lib/core/config.ts
1019
+ var init_config2 = __esm({
1020
+ "src/lib/core/config.ts"() {
1021
+ "use strict";
1022
+ init_constants2();
1023
+ init_context();
1024
+ init_logger();
1025
+ }
1026
+ });
1027
+
1028
+ // src/lib/auth/storage.ts
1029
+ var init_storage = __esm({
1030
+ "src/lib/auth/storage.ts"() {
1031
+ "use strict";
1032
+ init_constants2();
1033
+ init_config2();
1034
+ }
1035
+ });
1036
+
1037
+ // src/lib/core/client.ts
1038
+ import { PlaycademyClient } from "@playcademy/sdk";
1039
+ var init_client = __esm({
1040
+ "src/lib/core/client.ts"() {
1041
+ "use strict";
1042
+ init_storage();
1043
+ init_logger();
1044
+ init_config2();
1045
+ }
1046
+ });
913
1047
 
914
1048
  // src/lib/core/errors.ts
915
1049
  function getErrorMessage(error) {
@@ -920,34 +1054,141 @@ function getErrorMessage(error) {
920
1054
  }
921
1055
  return "Unknown error";
922
1056
  }
1057
+ var init_errors = __esm({
1058
+ "src/lib/core/errors.ts"() {
1059
+ "use strict";
1060
+ }
1061
+ });
1062
+
1063
+ // ../utils/src/uuid.ts
1064
+ var init_uuid = __esm({
1065
+ "../utils/src/uuid.ts"() {
1066
+ "use strict";
1067
+ }
1068
+ });
1069
+
1070
+ // ../utils/src/mime.ts
1071
+ var init_mime = __esm({
1072
+ "../utils/src/mime.ts"() {
1073
+ "use strict";
1074
+ }
1075
+ });
923
1076
 
924
1077
  // ../utils/src/ansi.ts
925
- var isInteractive = typeof process !== "undefined" && process.stdout?.isTTY && !process.env.CI && process.env.TERM !== "dumb";
1078
+ var isInteractive;
1079
+ var init_ansi = __esm({
1080
+ "../utils/src/ansi.ts"() {
1081
+ "use strict";
1082
+ isInteractive = typeof process !== "undefined" && process.stdout?.isTTY && !process.env.CI && process.env.TERM !== "dumb";
1083
+ }
1084
+ });
926
1085
 
927
1086
  // ../utils/src/spinner.ts
928
- var SPINNER_FRAMES = [
929
- 10251,
930
- 10265,
931
- 10297,
932
- 10296,
933
- 10300,
934
- 10292,
935
- 10278,
936
- 10279,
937
- 10247,
938
- 10255
939
- ].map((code) => String.fromCodePoint(code));
940
- var CHECK_MARK = String.fromCodePoint(10004);
941
- var CROSS_MARK = String.fromCodePoint(10006);
1087
+ var SPINNER_FRAMES, CHECK_MARK, CROSS_MARK;
1088
+ var init_spinner = __esm({
1089
+ "../utils/src/spinner.ts"() {
1090
+ "use strict";
1091
+ init_ansi();
1092
+ SPINNER_FRAMES = [
1093
+ 10251,
1094
+ 10265,
1095
+ 10297,
1096
+ 10296,
1097
+ 10300,
1098
+ 10292,
1099
+ 10278,
1100
+ 10279,
1101
+ 10247,
1102
+ 10255
1103
+ ].map((code) => String.fromCodePoint(code));
1104
+ CHECK_MARK = String.fromCodePoint(10004);
1105
+ CROSS_MARK = String.fromCodePoint(10006);
1106
+ }
1107
+ });
1108
+
1109
+ // ../utils/src/log.ts
1110
+ var init_log = __esm({
1111
+ "../utils/src/log.ts"() {
1112
+ "use strict";
1113
+ init_ansi();
1114
+ init_spinner();
1115
+ }
1116
+ });
1117
+
1118
+ // ../utils/src/name.ts
1119
+ var init_name = __esm({
1120
+ "../utils/src/name.ts"() {
1121
+ "use strict";
1122
+ }
1123
+ });
1124
+
1125
+ // ../utils/src/string.ts
1126
+ function pluralize(count, singular, plural) {
1127
+ return count === 1 ? singular : plural || `${singular}s`;
1128
+ }
1129
+ var init_string = __esm({
1130
+ "../utils/src/string.ts"() {
1131
+ "use strict";
1132
+ }
1133
+ });
1134
+
1135
+ // ../utils/src/lifecycle.ts
1136
+ var init_lifecycle = __esm({
1137
+ "../utils/src/lifecycle.ts"() {
1138
+ "use strict";
1139
+ }
1140
+ });
1141
+
1142
+ // ../utils/src/timezone.ts
1143
+ var init_timezone = __esm({
1144
+ "../utils/src/timezone.ts"() {
1145
+ "use strict";
1146
+ }
1147
+ });
1148
+
1149
+ // ../utils/src/slug.ts
1150
+ var init_slug = __esm({
1151
+ "../utils/src/slug.ts"() {
1152
+ "use strict";
1153
+ }
1154
+ });
942
1155
 
943
1156
  // ../utils/src/pure/index.ts
944
- init_package_json();
1157
+ var init_pure = __esm({
1158
+ "../utils/src/pure/index.ts"() {
1159
+ "use strict";
1160
+ init_uuid();
1161
+ init_mime();
1162
+ init_log();
1163
+ init_name();
1164
+ init_string();
1165
+ init_lifecycle();
1166
+ init_timezone();
1167
+ init_package_json();
1168
+ init_slug();
1169
+ }
1170
+ });
1171
+
1172
+ // ../utils/src/index.ts
1173
+ var init_src2 = __esm({
1174
+ "../utils/src/index.ts"() {
1175
+ "use strict";
1176
+ init_pure();
1177
+ }
1178
+ });
1179
+
1180
+ // src/lib/config/timeback-derive.ts
1181
+ var init_timeback_derive = __esm({
1182
+ "src/lib/config/timeback-derive.ts"() {
1183
+ "use strict";
1184
+ init_game();
1185
+ }
1186
+ });
945
1187
 
946
1188
  // src/lib/templates/loader.ts
947
1189
  import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
948
1190
  import { dirname as dirname3, resolve as resolve3 } from "path";
949
1191
  import { fileURLToPath } from "url";
950
- var currentDir = dirname3(fileURLToPath(import.meta.url));
951
1192
  function loadTemplateString(filename) {
952
1193
  const filenamesToTry = filename.endsWith(".template") ? [filename] : [filename, `${filename}.template`];
953
1194
  const candidatePaths = filenamesToTry.flatMap((name) => [
@@ -963,6 +1204,49 @@ function loadTemplateString(filename) {
963
1204
  }
964
1205
  throw new Error(`Template not found: ${filename}. Searched: ${candidatePaths.join(", ")}`);
965
1206
  }
1207
+ var currentDir;
1208
+ var init_loader2 = __esm({
1209
+ "src/lib/templates/loader.ts"() {
1210
+ "use strict";
1211
+ currentDir = dirname3(fileURLToPath(import.meta.url));
1212
+ }
1213
+ });
1214
+
1215
+ // src/lib/config/generator.ts
1216
+ var init_generator = __esm({
1217
+ "src/lib/config/generator.ts"() {
1218
+ "use strict";
1219
+ init_loader2();
1220
+ }
1221
+ });
1222
+
1223
+ // src/lib/config/writer.ts
1224
+ var init_writer = __esm({
1225
+ "src/lib/config/writer.ts"() {
1226
+ "use strict";
1227
+ }
1228
+ });
1229
+
1230
+ // src/lib/config/index.ts
1231
+ var init_config3 = __esm({
1232
+ "src/lib/config/index.ts"() {
1233
+ "use strict";
1234
+ init_loader();
1235
+ init_timeback_derive();
1236
+ init_generator();
1237
+ init_writer();
1238
+ }
1239
+ });
1240
+
1241
+ // src/lib/core/game.ts
1242
+ var init_game = __esm({
1243
+ "src/lib/core/game.ts"() {
1244
+ "use strict";
1245
+ init_src2();
1246
+ init_slug();
1247
+ init_config3();
1248
+ }
1249
+ });
966
1250
 
967
1251
  // src/lib/core/import.ts
968
1252
  import { mkdtempSync, rmSync } from "fs";
@@ -998,13 +1282,135 @@ async function importTypescriptDefault(filePath, bundleOptions) {
998
1282
  }
999
1283
  return module;
1000
1284
  }
1285
+ var init_import = __esm({
1286
+ "src/lib/core/import.ts"() {
1287
+ "use strict";
1288
+ }
1289
+ });
1290
+
1291
+ // src/lib/core/index.ts
1292
+ var init_core = __esm({
1293
+ "src/lib/core/index.ts"() {
1294
+ "use strict";
1295
+ init_client();
1296
+ init_config2();
1297
+ init_context();
1298
+ init_errors();
1299
+ init_game();
1300
+ init_import();
1301
+ init_logger();
1302
+ }
1303
+ });
1304
+
1305
+ // src/utils.ts
1306
+ init_loader();
1307
+ init_loader();
1308
+ init_loader();
1309
+
1310
+ // src/lib/dev/server.ts
1311
+ init_src();
1312
+ import { mkdir as mkdir2 } from "fs/promises";
1313
+ import { join as join12 } from "path";
1314
+ import { Log, LogLevel, Miniflare } from "miniflare";
1315
+
1316
+ // ../utils/src/port.ts
1317
+ import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "node:fs";
1318
+ import { createServer } from "node:net";
1319
+ import { homedir } from "node:os";
1320
+ import { join as join2 } from "node:path";
1321
+ async function isPortAvailableOnHost(port, host) {
1322
+ return new Promise((resolve4) => {
1323
+ const server = createServer();
1324
+ let resolved = false;
1325
+ const cleanup = (result) => {
1326
+ if (resolved) return;
1327
+ resolved = true;
1328
+ try {
1329
+ server.close();
1330
+ } catch {
1331
+ }
1332
+ resolve4(result);
1333
+ };
1334
+ const timeout = setTimeout(() => cleanup(true), 100);
1335
+ server.once("error", (err) => {
1336
+ clearTimeout(timeout);
1337
+ if (err.code === "EAFNOSUPPORT" || err.code === "EADDRNOTAVAIL") {
1338
+ cleanup(true);
1339
+ } else {
1340
+ cleanup(false);
1341
+ }
1342
+ });
1343
+ server.once("listening", () => {
1344
+ clearTimeout(timeout);
1345
+ cleanup(true);
1346
+ });
1347
+ server.listen(port, host).unref();
1348
+ });
1349
+ }
1350
+ async function findAvailablePort(startPort = 4321) {
1351
+ if (await isPortAvailableOnHost(startPort, "0.0.0.0")) {
1352
+ return startPort;
1353
+ } else {
1354
+ return findAvailablePort(startPort + 1);
1355
+ }
1356
+ }
1357
+ function getRegistryPath() {
1358
+ const home = homedir();
1359
+ const dir = join2(home, ".playcademy");
1360
+ if (!existsSync2(dir)) {
1361
+ mkdirSync(dir, { recursive: true });
1362
+ }
1363
+ return join2(dir, ".proc");
1364
+ }
1365
+ function readRegistry() {
1366
+ const registryPath = getRegistryPath();
1367
+ if (!existsSync2(registryPath)) {
1368
+ return {};
1369
+ }
1370
+ try {
1371
+ const content = readFileSync(registryPath, "utf-8");
1372
+ return JSON.parse(content);
1373
+ } catch {
1374
+ return {};
1375
+ }
1376
+ }
1377
+ function writeRegistry(registry) {
1378
+ const registryPath = getRegistryPath();
1379
+ writeFileSync(registryPath, JSON.stringify(registry, null, 2), "utf-8");
1380
+ }
1381
+ function getServerKey(type, port) {
1382
+ return `${type}-${port}`;
1383
+ }
1384
+ function writeServerInfo(type, info) {
1385
+ const registry = readRegistry();
1386
+ const key = getServerKey(type, info.port);
1387
+ registry[key] = info;
1388
+ writeRegistry(registry);
1389
+ }
1390
+ function readServerInfo(type, projectRoot) {
1391
+ const registry = readRegistry();
1392
+ const servers = Object.entries(registry).filter(([key]) => key.startsWith(`${type}-`)).map(([, info]) => info);
1393
+ if (servers.length === 0) {
1394
+ return null;
1395
+ }
1396
+ if (projectRoot) {
1397
+ const match = servers.find((s) => s.projectRoot === projectRoot);
1398
+ return match || null;
1399
+ }
1400
+ return servers[0] || null;
1401
+ }
1402
+
1403
+ // src/lib/dev/server.ts
1404
+ init_constants2();
1405
+ init_loader();
1406
+ init_core();
1001
1407
 
1002
1408
  // src/lib/deploy/bundle.ts
1003
1409
  import { existsSync as existsSync5 } from "fs";
1004
1410
  import { join as join6 } from "path";
1005
1411
 
1006
1412
  // ../edge-play/src/entry.ts
1007
- var entry_default = "/**\n * Game Backend Entry Point\n *\n * This file is the main entry point for deployed game backends.\n * It creates a Hono app and registers all enabled integration routes.\n *\n * Bundled with esbuild and deployed to Cloudflare Workers (or AWS Lambda).\n * Config is injected at build time via esbuild's `define` option.\n */\n\nimport { Hono } from 'hono'\nimport { cors } from 'hono/cors'\n\nimport { PlaycademyClient } from '@playcademy/sdk/server'\n\nimport { ENV_VARS } from './constants'\nimport { registerBuiltinRoutes } from './register-routes'\n\nimport type { PlaycademyConfig } from '@playcademy/sdk/server'\nimport type { HonoEnv } from './types'\n\n/**\n * Config injected at build time by esbuild\n *\n * The `declare const` tells TypeScript \"this exists at runtime, trust me.\"\n * During bundling, esbuild's `define` option does literal text replacement:\n *\n * Example bundling:\n * Source: if (PLAYCADEMY_CONFIG.integrations.timeback) { ... }\n * Define: { 'PLAYCADEMY_CONFIG': JSON.stringify({ integrations: { timeback: {...} } }) }\n * Output: if ({\"integrations\":{\"timeback\":{...}}}.integrations.timeback) { ... }\n *\n * This enables tree-shaking: if timeback is not configured, those code paths are removed.\n * The bundled Worker only includes the routes that are actually enabled.\n */\ndeclare const PLAYCADEMY_CONFIG: PlaycademyConfig & {\n customRoutes?: Array<{ path: string; file: string }>\n}\n\n// XXX: Polyfill process global for SDK compatibility\n// SDK code may reference process.env without importing it\n// @ts-expect-error - Adding global for Worker environment\nglobalThis.process = {\n env: {}, // Populated per-request from Worker env bindings\n cwd: () => '/',\n}\n\nconst app = new Hono<HonoEnv>()\n\n// TODO: Harden CORS in production - restrict to trusted origins:\n// - Game's assetBundleBase (for hosted games)\n// - Game's externalUrl (for external games)\n// - Platform frontend domains (hub.playcademy.com, hub.dev.playcademy.net)\n// This would require passing game metadata through env bindings during deployment\napp.use(\n '*',\n cors({\n origin: '*', // Permissive for now\n allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Authorization'],\n }),\n)\n\nlet sdkPromise: Promise<PlaycademyClient> | null = null\n\napp.use('*', async (c, next) => {\n // Populate process.env from Worker bindings for SDK compatibility\n globalThis.process.env = {\n [ENV_VARS.PLAYCADEMY_API_KEY]: c.env.PLAYCADEMY_API_KEY,\n [ENV_VARS.GAME_ID]: c.env.GAME_ID,\n [ENV_VARS.PLAYCADEMY_BASE_URL]: c.env.PLAYCADEMY_BASE_URL,\n }\n\n // Set config for all routes\n c.set('config', PLAYCADEMY_CONFIG)\n c.set('customRoutes', PLAYCADEMY_CONFIG.customRoutes || [])\n\n await next()\n})\n\n// Initialize SDK lazily on first request\napp.use('*', async (c, next) => {\n if (!sdkPromise) {\n sdkPromise = PlaycademyClient.init({\n apiKey: c.env[ENV_VARS.PLAYCADEMY_API_KEY],\n gameId: c.env[ENV_VARS.GAME_ID],\n baseUrl: c.env[ENV_VARS.PLAYCADEMY_BASE_URL],\n config: PLAYCADEMY_CONFIG,\n })\n }\n\n c.set('sdk', await sdkPromise)\n await next()\n})\n\n/**\n * Register built-in integration routes based on enabled integrations\n *\n * This function conditionally imports and registers routes like:\n * - POST /api/integrations/timeback/end-activity (if timeback enabled)\n * - GET /api/health (always included)\n *\n * Uses dynamic imports for tree-shaking: if an integration is not enabled,\n * its route code is completely removed from the bundle.\n */\nawait registerBuiltinRoutes(app, PLAYCADEMY_CONFIG.integrations)\n\nexport default app\n";
1413
+ var entry_default = "/**\n * Game Backend Entry Point\n *\n * This file is the main entry point for deployed game backends.\n * It creates a Hono app and registers all enabled integration routes.\n *\n * Bundled with esbuild and deployed to Cloudflare Workers (or AWS Lambda).\n * Config is injected at build time via esbuild's `define` option.\n */\n\nimport { Hono } from 'hono'\n\nimport { registerCors, registerEnvSetup, registerSdkInit } from './entry/middleware'\nimport { setupProcessGlobal } from './entry/setup'\nimport { registerBuiltinRoutes } from './register-routes'\n\nimport type { RuntimeConfig } from './entry/types'\nimport type { HonoEnv } from './types'\n\n/**\n * Config injected at build time by esbuild\n *\n * The `declare const` tells TypeScript \"this exists at runtime, trust me.\"\n * During bundling, esbuild's `define` option does literal text replacement:\n *\n * Example bundling:\n * Source: if (PLAYCADEMY_CONFIG.integrations.timeback) { ... }\n * Define: { 'PLAYCADEMY_CONFIG': JSON.stringify({ integrations: { timeback: {...} } }) }\n * Output: if ({\"integrations\":{\"timeback\":{...}}}.integrations.timeback) { ... }\n *\n * This enables tree-shaking: if timeback is not configured, those code paths are removed.\n * The bundled Worker only includes the routes that are actually enabled.\n */\ndeclare const PLAYCADEMY_CONFIG: RuntimeConfig\n\n// Setup process global polyfill for SDK compatibility\nsetupProcessGlobal()\n\n// Create Hono app\nconst app = new Hono<HonoEnv>()\n\n// Register middleware\nregisterCors(app)\nregisterEnvSetup(app, PLAYCADEMY_CONFIG)\nregisterSdkInit(app, PLAYCADEMY_CONFIG)\n\n// Register built-in integration routes based on enabled integrations\n// This function conditionally imports and registers routes like:\n// - GET /api (always included)\n// - GET /api/health (always included)\n// - POST /api/integrations/timeback/end-activity (if timeback enabled)\n//\n// Uses dynamic imports for tree-shaking: if an integration is not enabled,\n// its route code is completely removed from the bundle.\nawait registerBuiltinRoutes(app, PLAYCADEMY_CONFIG.integrations)\n\nexport default app\n";
1008
1414
 
1009
1415
  // ../utils/src/path.ts
1010
1416
  import fs from "node:fs";
@@ -1220,6 +1626,9 @@ function getMonorepoRoot() {
1220
1626
  return memoizedRoot;
1221
1627
  }
1222
1628
 
1629
+ // src/lib/deploy/bundle.ts
1630
+ init_constants2();
1631
+
1223
1632
  // src/lib/build/plugins.ts
1224
1633
  function textLoaderPlugin() {
1225
1634
  return {
@@ -1253,8 +1662,12 @@ function textLoaderPlugin() {
1253
1662
  };
1254
1663
  }
1255
1664
 
1665
+ // src/lib/deploy/bundle.ts
1666
+ init_core();
1667
+
1256
1668
  // src/lib/dev/routes.ts
1257
1669
  init_file_loader();
1670
+ init_core();
1258
1671
  import { mkdir, writeFile } from "fs/promises";
1259
1672
  import { tmpdir as tmpdir2 } from "os";
1260
1673
  import { join as join5, relative } from "path";
@@ -1454,7 +1867,7 @@ async function bundleBackend(config, options = {}) {
1454
1867
  const { customRouteData, customRoutesDir } = await discoverCustomRoutes(config);
1455
1868
  const bundleConfig = {
1456
1869
  ...config,
1457
- customRoutes: customRouteData
1870
+ __routeMetadata: customRouteData
1458
1871
  };
1459
1872
  const entryCode = generateEntryCode(customRouteData, customRoutesDir);
1460
1873
  const paths = resolveEmbeddedSourcePaths();
@@ -1504,8 +1917,19 @@ function generateEntryCode(customRoutes, customRoutesDir) {
1504
1917
  // src/lib/init/prompts.ts
1505
1918
  import { checkbox, confirm, input, select } from "@inquirer/prompts";
1506
1919
  import { bold as bold3, cyan as cyan2 } from "colorette";
1920
+ init_constants2();
1921
+
1922
+ // src/lib/init/scaffold.ts
1923
+ init_constants2();
1924
+ init_core();
1925
+ init_loader2();
1507
1926
 
1508
1927
  // src/lib/init/database.ts
1928
+ init_log();
1929
+ init_slug();
1930
+ init_core();
1931
+ init_logger();
1932
+ init_loader2();
1509
1933
  import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
1510
1934
  import { join as join7 } from "path";
1511
1935
  var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
@@ -1530,7 +1954,9 @@ var sampleBucketRouteTemplate = loadTemplateString("api/sample-bucket.ts");
1530
1954
  var playcademyGitignoreTemplate = loadTemplateString("playcademy-gitignore");
1531
1955
 
1532
1956
  // src/lib/init/display.ts
1533
- import { blueBright } from "colorette";
1957
+ init_package_manager();
1958
+ init_context();
1959
+ init_logger();
1534
1960
 
1535
1961
  // src/lib/init/kv.ts
1536
1962
  function hasKVSetup(config) {
@@ -1544,57 +1970,292 @@ function hasBucketSetup(config) {
1544
1970
 
1545
1971
  // src/lib/init/types.ts
1546
1972
  init_file_loader();
1973
+ init_package_manager();
1974
+ init_string();
1975
+ init_constants2();
1976
+ init_loader();
1977
+ init_core();
1547
1978
  import { execSync as execSync2 } from "child_process";
1548
- import { writeFileSync as writeFileSync3 } from "fs";
1549
- import { dirname as dirname4, join as join8 } from "path";
1979
+ import { writeFileSync as writeFileSync4 } from "fs";
1980
+ import { dirname as dirname4, join as join11 } from "path";
1550
1981
  import { fileURLToPath as fileURLToPath2 } from "url";
1982
+
1983
+ // src/lib/deploy/backend.ts
1984
+ init_src2();
1985
+ init_constants2();
1986
+ init_core();
1987
+ import { existsSync as existsSync7 } from "node:fs";
1988
+ import { join as join8 } from "node:path";
1989
+
1990
+ // src/lib/integrations/timeback.ts
1991
+ init_src2();
1992
+ init_core();
1993
+
1994
+ // src/lib/integrations/utils.ts
1995
+ init_string();
1996
+
1997
+ // src/lib/deploy/schema.ts
1998
+ init_core();
1999
+
2000
+ // src/lib/deploy/secrets.ts
2001
+ init_core();
2002
+ init_logger();
2003
+
2004
+ // src/lib/deploy/utils.ts
2005
+ init_src();
2006
+
2007
+ // src/lib/deploy/backend.ts
2008
+ function getCustomRoutesDirectory(projectPath, config) {
2009
+ const customRoutes = config?.integrations?.customRoutes;
2010
+ const customRoutesDir = typeof customRoutes === "object" && customRoutes.directory || DEFAULT_API_ROUTES_DIRECTORY;
2011
+ return join8(projectPath, customRoutesDir);
2012
+ }
2013
+ function hasLocalCustomRoutes(projectPath, config) {
2014
+ const customRoutesDir = getCustomRoutesDirectory(projectPath, config);
2015
+ return existsSync7(customRoutesDir);
2016
+ }
2017
+
2018
+ // src/lib/secrets/env.ts
2019
+ init_file_loader();
2020
+ init_constants2();
2021
+ import { existsSync as existsSync8 } from "fs";
2022
+ import { join as join9 } from "path";
2023
+ function parseEnvFile(contents) {
2024
+ const secrets = {};
2025
+ for (const line of contents.split("\n")) {
2026
+ const trimmed = line.trim();
2027
+ if (!trimmed || trimmed.startsWith("#")) {
2028
+ continue;
2029
+ }
2030
+ const match = trimmed.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
2031
+ if (match) {
2032
+ const [, key, value] = match;
2033
+ if (!key || !value) {
2034
+ continue;
2035
+ }
2036
+ const unquoted = value.replace(/^["']|["']$/g, "");
2037
+ secrets[key] = unquoted;
2038
+ }
2039
+ }
2040
+ return secrets;
2041
+ }
2042
+ async function readEnvFile(workspace) {
2043
+ let secrets = {};
2044
+ for (const filename of ENV_FILES) {
2045
+ try {
2046
+ const contents = await loadFile(filename, { cwd: workspace, searchUp: false });
2047
+ if (contents) {
2048
+ const fileSecrets = parseEnvFile(contents);
2049
+ secrets = { ...secrets, ...fileSecrets };
2050
+ }
2051
+ } catch {
2052
+ continue;
2053
+ }
2054
+ }
2055
+ return secrets;
2056
+ }
2057
+ function getLoadedEnvFiles(workspace) {
2058
+ return ENV_FILES.filter((filename) => existsSync8(join9(workspace, filename)));
2059
+ }
2060
+ function hasEnvFile(workspace) {
2061
+ return ENV_FILES.some((filename) => existsSync8(join9(workspace, filename)));
2062
+ }
2063
+
2064
+ // src/lib/init/types.ts
2065
+ init_loader2();
2066
+
2067
+ // src/lib/init/tsconfig.ts
2068
+ init_file_loader();
2069
+ init_constants2();
2070
+ import { existsSync as existsSync9, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
2071
+ import { join as join10 } from "path";
2072
+ function hasPlaycademyEnv(config) {
2073
+ return config.include?.includes("playcademy-env.d.ts") ?? false;
2074
+ }
2075
+ function addPlaycademyEnv(config) {
2076
+ if (!config.include) {
2077
+ config.include = [];
2078
+ }
2079
+ config.include.push("playcademy-env.d.ts");
2080
+ }
2081
+ function updateExistingIncludeArray(content) {
2082
+ const includeRegex = /"include"\s*:\s*\[([^\]]*)\]/;
2083
+ const match = content.match(includeRegex);
2084
+ if (!match || !match[1]) {
2085
+ return null;
2086
+ }
2087
+ const fullMatch = match[0];
2088
+ const arrayContents = match[1];
2089
+ if (arrayContents.includes("playcademy-env.d.ts")) {
2090
+ return content;
2091
+ }
2092
+ const trimmedContents = arrayContents.trim();
2093
+ const newEntry = '"playcademy-env.d.ts"';
2094
+ let newArrayContents;
2095
+ if (trimmedContents === "") {
2096
+ newArrayContents = newEntry;
2097
+ } else if (arrayContents.includes("\n")) {
2098
+ newArrayContents = `${arrayContents},
2099
+ ${newEntry}
2100
+ `;
2101
+ } else {
2102
+ newArrayContents = `${trimmedContents}, ${newEntry}`;
2103
+ }
2104
+ const newIncludeArray = `"include": [${newArrayContents}]`;
2105
+ return content.replace(fullMatch, newIncludeArray);
2106
+ }
2107
+ function addNewIncludeProperty(content) {
2108
+ const closingBraceMatch = content.match(/\n(\s*)\}(\s*)$/);
2109
+ if (!closingBraceMatch || closingBraceMatch.index === void 0) {
2110
+ return null;
2111
+ }
2112
+ const propertyMatch = content.match(/\n(\s+)"/);
2113
+ const propertyIndent = propertyMatch ? propertyMatch[1] : " ";
2114
+ const insertPosition = closingBraceMatch.index;
2115
+ const beforeClosing = content.slice(0, insertPosition).trim();
2116
+ const needsComma = beforeClosing.endsWith("]") || beforeClosing.endsWith("}") || beforeClosing.endsWith('"');
2117
+ const comma = needsComma ? "," : "";
2118
+ const includeEntry = `${comma}
2119
+ ${propertyIndent}"include": ["playcademy-env.d.ts"]`;
2120
+ const updatedContent = content.slice(0, insertPosition) + includeEntry + content.slice(insertPosition);
2121
+ return updatedContent;
2122
+ }
2123
+ function addToIncludeArrayPreservingComments(content) {
2124
+ return updateExistingIncludeArray(content) || addNewIncludeProperty(content);
2125
+ }
2126
+ async function ensureTsconfigIncludes(workspace) {
2127
+ for (const filename of TSCONFIG_FILES) {
2128
+ const configPath = join10(workspace, filename);
2129
+ if (!existsSync9(configPath)) {
2130
+ continue;
2131
+ }
2132
+ try {
2133
+ const config = await loadFile(configPath, {
2134
+ parseJson: true,
2135
+ stripComments: true
2136
+ });
2137
+ if (!config) continue;
2138
+ if (config.references && filename !== "tsconfig.json") {
2139
+ continue;
2140
+ }
2141
+ if (hasPlaycademyEnv(config)) {
2142
+ return filename;
2143
+ }
2144
+ try {
2145
+ const rawContent = readFileSync4(configPath, "utf-8");
2146
+ const updatedContent = addToIncludeArrayPreservingComments(rawContent);
2147
+ if (updatedContent && updatedContent !== rawContent) {
2148
+ writeFileSync3(configPath, updatedContent);
2149
+ return filename;
2150
+ }
2151
+ } catch {
2152
+ }
2153
+ addPlaycademyEnv(config);
2154
+ writeFileSync3(configPath, JSON.stringify(config, null, 4) + "\n");
2155
+ return filename;
2156
+ } catch {
2157
+ continue;
2158
+ }
2159
+ }
2160
+ return null;
2161
+ }
2162
+
2163
+ // src/lib/init/types.ts
1551
2164
  var playcademyEnvTemplate = loadTemplateString("playcademy-env.d.ts");
1552
- async function ensurePlaycademyTypes() {
2165
+ function detectBackendFeatures(workspace, config) {
2166
+ return {
2167
+ hasDB: hasDatabaseSetup(),
2168
+ hasKV: hasKVSetup(config),
2169
+ hasBucket: hasBucketSetup(config),
2170
+ hasRoutes: hasLocalCustomRoutes(workspace, config),
2171
+ hasSecrets: hasEnvFile(workspace)
2172
+ };
2173
+ }
2174
+ function hasAnyBackend(features) {
2175
+ return Object.values(features).some(Boolean);
2176
+ }
2177
+ async function setupPlaycademyDependencies(workspace) {
2178
+ const playcademyDir = join11(workspace, CLI_DIRECTORIES.WORKSPACE);
2179
+ const playcademyPkgPath = join11(playcademyDir, "package.json");
2180
+ const __dirname = dirname4(fileURLToPath2(import.meta.url));
2181
+ const cliPkg = await loadPackageJson({ cwd: __dirname, searchUp: true, required: true });
2182
+ const workersTypesVersion = cliPkg?.devDependencies?.["@cloudflare/workers-types"] || "latest";
2183
+ const honoVersion = cliPkg?.dependencies?.hono || "latest";
2184
+ const playcademyPkg = {
2185
+ private: true,
2186
+ dependencies: { hono: honoVersion },
2187
+ devDependencies: { "@cloudflare/workers-types": workersTypesVersion }
2188
+ };
2189
+ writeFileSync4(playcademyPkgPath, JSON.stringify(playcademyPkg, null, 4) + "\n");
2190
+ const pm = detectPackageManager(workspace);
2191
+ const installCmd = getInstallCommand(pm);
2192
+ execSync2(installCmd, {
2193
+ cwd: playcademyDir,
2194
+ stdio: ["ignore", "ignore", "ignore"]
2195
+ });
2196
+ }
2197
+ function generateBindingsTypeString(features) {
2198
+ const bindings = [];
2199
+ if (features.hasKV) bindings.push(" KV: KVNamespace");
2200
+ if (features.hasDB) bindings.push(" DB: D1Database");
2201
+ if (features.hasBucket) bindings.push(" BUCKET: R2Bucket");
2202
+ return bindings.length > 0 ? "\n" + bindings.join("\n") : "";
2203
+ }
2204
+ async function generateSecretsTypeString(workspace, verbose = false) {
2205
+ try {
2206
+ const envSecrets = await readEnvFile(workspace);
2207
+ const secretKeys = Object.keys(envSecrets);
2208
+ if (secretKeys.length === 0) {
2209
+ if (verbose) logger.success("No secrets in <.env> files");
2210
+ return "\n secrets: Record<string, string>";
2211
+ }
2212
+ if (verbose) {
2213
+ const loadedFiles = getLoadedEnvFiles(workspace);
2214
+ const fileList = loadedFiles.map((f) => `<${f}>`).join(", ");
2215
+ logger.success(
2216
+ `Loaded ${secretKeys.length} ${pluralize(secretKeys.length, "secret")} from ${fileList}`
2217
+ );
2218
+ }
2219
+ const secretTypes = secretKeys.map((key) => ` ${key}: string`).join("\n");
2220
+ return `
2221
+ secrets: {
2222
+ ${secretTypes}
2223
+ [key: string]: string
2224
+ }`;
2225
+ } catch {
2226
+ return "\n secrets: Record<string, string>";
2227
+ }
2228
+ }
2229
+ async function ensurePlaycademyTypes(options = {}) {
2230
+ const { verbose = false } = options;
1553
2231
  try {
1554
2232
  const workspace = getWorkspace();
1555
2233
  const config = await loadConfig();
1556
- const hasDB = hasDatabaseSetup();
1557
- const hasKV = hasKVSetup(config);
1558
- const hasBucket = hasBucketSetup(config);
1559
- if (!hasDB && !hasKV && !hasBucket) {
2234
+ const features = detectBackendFeatures(workspace, config);
2235
+ if (!hasAnyBackend(features)) {
2236
+ if (verbose) {
2237
+ logger.dim("No backend functionality detected");
2238
+ }
1560
2239
  return;
1561
2240
  }
1562
- const playcademyDir = join8(workspace, CLI_DIRECTORIES.WORKSPACE);
1563
- const playcademyPkgPath = join8(playcademyDir, "package.json");
1564
- const __dirname = dirname4(fileURLToPath2(import.meta.url));
1565
- const cliPkg = await loadPackageJson({ cwd: __dirname, searchUp: true, required: true });
1566
- const workersTypesVersion = cliPkg?.devDependencies?.["@cloudflare/workers-types"] || "latest";
1567
- const honoVersion = cliPkg?.dependencies?.hono || "latest";
1568
- const playcademyPkg = {
1569
- private: true,
1570
- dependencies: {
1571
- hono: honoVersion
1572
- },
1573
- devDependencies: {
1574
- "@cloudflare/workers-types": workersTypesVersion
1575
- }
1576
- };
1577
- writeFileSync3(playcademyPkgPath, JSON.stringify(playcademyPkg, null, 4) + "\n");
1578
- const pm = detectPackageManager(workspace);
1579
- const installCmd = getInstallCommand(pm);
1580
- execSync2(installCmd, {
1581
- cwd: playcademyDir,
1582
- stdio: ["ignore", "ignore", "ignore"]
1583
- });
1584
- const bindings = [];
1585
- if (hasKV) {
1586
- bindings.push(" KV: KVNamespace");
2241
+ await setupPlaycademyDependencies(workspace);
2242
+ if (verbose) {
2243
+ logger.success(`Installed packages in <${CLI_DIRECTORIES.WORKSPACE}>`);
1587
2244
  }
1588
- if (hasDB) {
1589
- bindings.push(" DB: D1Database");
2245
+ const bindingsStr = generateBindingsTypeString(features);
2246
+ const secretsStr = await generateSecretsTypeString(workspace, verbose);
2247
+ let envContent = playcademyEnvTemplate.replace("{{BINDINGS}}", bindingsStr);
2248
+ envContent = envContent.replace("{{SECRETS}}", secretsStr);
2249
+ const envPath = join11(workspace, "playcademy-env.d.ts");
2250
+ writeFileSync4(envPath, envContent);
2251
+ if (verbose) {
2252
+ logger.success(`Generated <playcademy-env.d.ts>`);
1590
2253
  }
1591
- if (hasBucket) {
1592
- bindings.push(" BUCKET: R2Bucket");
2254
+ const tsConfigFilename = await ensureTsconfigIncludes(workspace);
2255
+ if (verbose) {
2256
+ logger.success(`Updated <${tsConfigFilename}>`);
1593
2257
  }
1594
- const bindingsStr = bindings.length > 0 ? "\n" + bindings.join("\n") : "";
1595
- const envContent = playcademyEnvTemplate.replace("{{BINDINGS}}", bindingsStr);
1596
- const envPath = join8(workspace, "playcademy-env.d.ts");
1597
- writeFileSync3(envPath, envContent);
2258
+ logger.newLine();
1598
2259
  } catch (error) {
1599
2260
  logger.warn(
1600
2261
  `Failed to generate TypeScript types: ${error instanceof Error ? error.message : String(error)}`
@@ -1603,6 +2264,8 @@ async function ensurePlaycademyTypes() {
1603
2264
  }
1604
2265
 
1605
2266
  // src/lib/init/gitignore.ts
2267
+ init_core();
2268
+ init_loader2();
1606
2269
  var rootGitignoreTemplate = loadTemplateString("gitignore");
1607
2270
 
1608
2271
  // src/lib/dev/server.ts
@@ -1629,9 +2292,19 @@ async function startDevServer(options) {
1629
2292
  const kvDir = hasKV ? await ensureKvDirectory() : void 0;
1630
2293
  const hasBucket = hasBucketSetup(config);
1631
2294
  const bucketDir = hasBucket ? await ensureBucketDirectory() : void 0;
2295
+ const workspace = getWorkspace();
2296
+ const envSecrets = await readEnvFile(workspace);
1632
2297
  const log2 = logger2 ? new FilteredLog(LogLevel.INFO) : new Log(LogLevel.NONE);
1633
- const sandboxInfo = readServerInfo("sandbox", getWorkspace());
2298
+ const sandboxInfo = readServerInfo("sandbox", workspace);
1634
2299
  const baseUrl = platformUrl ?? sandboxInfo?.url ?? process.env.PLAYCADEMY_BASE_URL ?? `http://localhost:${DEFAULT_PORTS.SANDBOX}`;
2300
+ const bindings = {
2301
+ PLAYCADEMY_API_KEY: process.env.PLAYCADEMY_API_KEY || "dev-api-key",
2302
+ GAME_ID: CORE_GAME_UUIDS.PLAYGROUND,
2303
+ PLAYCADEMY_BASE_URL: baseUrl
2304
+ };
2305
+ for (const [key, value] of Object.entries(envSecrets)) {
2306
+ bindings[`secrets_${key}`] = value;
2307
+ }
1635
2308
  const mf = new Miniflare({
1636
2309
  port,
1637
2310
  log: log2,
@@ -1642,11 +2315,7 @@ async function startDevServer(options) {
1642
2315
  contents: bundle.code
1643
2316
  }
1644
2317
  ],
1645
- bindings: {
1646
- PLAYCADEMY_API_KEY: process.env.PLAYCADEMY_API_KEY || "dev-api-key",
1647
- GAME_ID: CORE_GAME_UUIDS.PLAYGROUND,
1648
- PLAYCADEMY_BASE_URL: baseUrl
1649
- },
2318
+ bindings,
1650
2319
  d1Databases: hasDatabase ? ["DB"] : [],
1651
2320
  d1Persist: dbDir,
1652
2321
  kvNamespaces: hasKV ? ["KV"] : [],
@@ -1662,7 +2331,7 @@ async function startDevServer(options) {
1662
2331
  return { server: mf, port };
1663
2332
  }
1664
2333
  async function ensureDatabaseDirectory() {
1665
- const dbDir = join9(getWorkspace(), CLI_DIRECTORIES.DATABASE);
2334
+ const dbDir = join12(getWorkspace(), CLI_DIRECTORIES.DATABASE);
1666
2335
  try {
1667
2336
  await mkdir2(dbDir, { recursive: true });
1668
2337
  } catch (error) {
@@ -1671,7 +2340,7 @@ async function ensureDatabaseDirectory() {
1671
2340
  return dbDir;
1672
2341
  }
1673
2342
  async function ensureKvDirectory() {
1674
- const kvDir = join9(getWorkspace(), CLI_DIRECTORIES.KV);
2343
+ const kvDir = join12(getWorkspace(), CLI_DIRECTORIES.KV);
1675
2344
  try {
1676
2345
  await mkdir2(kvDir, { recursive: true });
1677
2346
  } catch (error) {
@@ -1680,7 +2349,7 @@ async function ensureKvDirectory() {
1680
2349
  return kvDir;
1681
2350
  }
1682
2351
  async function ensureBucketDirectory() {
1683
- const bucketDir = join9(getWorkspace(), CLI_DIRECTORIES.BUCKET);
2352
+ const bucketDir = join12(getWorkspace(), CLI_DIRECTORIES.BUCKET);
1684
2353
  try {
1685
2354
  await mkdir2(bucketDir, { recursive: true });
1686
2355
  } catch (error) {
@@ -1703,7 +2372,9 @@ async function writeBackendServerInfo(port) {
1703
2372
  }
1704
2373
 
1705
2374
  // src/lib/dev/reload.ts
1706
- import { join as join10, relative as relative2 } from "path";
2375
+ init_constants2();
2376
+ init_core();
2377
+ import { join as join13, relative as relative2 } from "path";
1707
2378
  import chokidar from "chokidar";
1708
2379
  import { bold as bold4, cyan as cyan3, dim as dim3, green as green2 } from "colorette";
1709
2380
  function formatTime() {
@@ -1720,9 +2391,9 @@ function startHotReload(onReload, options = {}) {
1720
2391
  const customRoutesConfig = options.config?.integrations?.customRoutes;
1721
2392
  const customRoutesDir = typeof customRoutesConfig === "object" && customRoutesConfig.directory || DEFAULT_API_ROUTES_DIRECTORY;
1722
2393
  const watchPaths = [
1723
- join10(workspace, customRoutesDir),
1724
- join10(workspace, "playcademy.config.js"),
1725
- join10(workspace, "playcademy.config.json")
2394
+ join13(workspace, customRoutesDir),
2395
+ join13(workspace, "playcademy.config.js"),
2396
+ join13(workspace, "playcademy.config.json")
1726
2397
  ];
1727
2398
  const watcher = chokidar.watch(watchPaths, {
1728
2399
  persistent: true,
@@ -1760,6 +2431,9 @@ function startHotReload(onReload, options = {}) {
1760
2431
  watcher.on("unlink", createReloadHandler("removed"));
1761
2432
  return watcher;
1762
2433
  }
2434
+
2435
+ // src/utils.ts
2436
+ init_import();
1763
2437
  export {
1764
2438
  findConfigPath as findPlaycademyConfigPath,
1765
2439
  importTypescriptDefault,