playcademy 0.13.19 → 0.13.21

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,199 @@ 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
+ customRaw: (text, indent = 0) => {
994
+ const spaces = " ".repeat(indent);
995
+ console.log(`${spaces}${customTransform(text)}`);
996
+ },
997
+ /**
998
+ * Display a configuration error with helpful suggestions
999
+ */
1000
+ configError: (error, indent = 0) => {
1001
+ const spaces = " ".repeat(indent);
1002
+ const isConfigError = error && typeof error === "object" && "name" in error && error.name === "ConfigError";
1003
+ if (isConfigError && "message" in error && "field" in error && "suggestion" in error) {
1004
+ const configErr = error;
1005
+ console.error(`${spaces}${red("\u2716")} ${bold(configErr.message)}`);
1006
+ if (configErr.field) {
1007
+ console.error(`${spaces} ${dim("Field:")} ${configErr.field}`);
1008
+ }
1009
+ if (configErr.suggestion) {
1010
+ console.error(`${spaces} ${dim("Fix:")} ${configErr.suggestion}`);
1011
+ }
1012
+ } else if (error instanceof Error) {
1013
+ console.error(`${spaces}${red("\u2716")} ${bold(error.message)}`);
1014
+ } else {
1015
+ console.error(`${spaces}${red("\u2716")} ${bold(String(error))}`);
1016
+ }
905
1017
  }
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
- }
1018
+ };
911
1019
  }
912
- };
1020
+ });
1021
+
1022
+ // src/lib/core/config.ts
1023
+ var init_config2 = __esm({
1024
+ "src/lib/core/config.ts"() {
1025
+ "use strict";
1026
+ init_constants2();
1027
+ init_context();
1028
+ init_logger();
1029
+ }
1030
+ });
1031
+
1032
+ // src/lib/auth/storage.ts
1033
+ var init_storage = __esm({
1034
+ "src/lib/auth/storage.ts"() {
1035
+ "use strict";
1036
+ init_constants2();
1037
+ init_config2();
1038
+ }
1039
+ });
1040
+
1041
+ // src/lib/core/client.ts
1042
+ import { PlaycademyClient } from "@playcademy/sdk";
1043
+ var init_client = __esm({
1044
+ "src/lib/core/client.ts"() {
1045
+ "use strict";
1046
+ init_storage();
1047
+ init_logger();
1048
+ init_config2();
1049
+ }
1050
+ });
913
1051
 
914
1052
  // src/lib/core/errors.ts
915
1053
  function getErrorMessage(error) {
@@ -920,34 +1058,141 @@ function getErrorMessage(error) {
920
1058
  }
921
1059
  return "Unknown error";
922
1060
  }
1061
+ var init_errors = __esm({
1062
+ "src/lib/core/errors.ts"() {
1063
+ "use strict";
1064
+ }
1065
+ });
1066
+
1067
+ // ../utils/src/uuid.ts
1068
+ var init_uuid = __esm({
1069
+ "../utils/src/uuid.ts"() {
1070
+ "use strict";
1071
+ }
1072
+ });
1073
+
1074
+ // ../utils/src/mime.ts
1075
+ var init_mime = __esm({
1076
+ "../utils/src/mime.ts"() {
1077
+ "use strict";
1078
+ }
1079
+ });
923
1080
 
924
1081
  // ../utils/src/ansi.ts
925
- var isInteractive = typeof process !== "undefined" && process.stdout?.isTTY && !process.env.CI && process.env.TERM !== "dumb";
1082
+ var isInteractive;
1083
+ var init_ansi = __esm({
1084
+ "../utils/src/ansi.ts"() {
1085
+ "use strict";
1086
+ isInteractive = typeof process !== "undefined" && process.stdout?.isTTY && !process.env.CI && process.env.TERM !== "dumb";
1087
+ }
1088
+ });
926
1089
 
927
1090
  // ../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);
1091
+ var SPINNER_FRAMES, CHECK_MARK, CROSS_MARK;
1092
+ var init_spinner = __esm({
1093
+ "../utils/src/spinner.ts"() {
1094
+ "use strict";
1095
+ init_ansi();
1096
+ SPINNER_FRAMES = [
1097
+ 10251,
1098
+ 10265,
1099
+ 10297,
1100
+ 10296,
1101
+ 10300,
1102
+ 10292,
1103
+ 10278,
1104
+ 10279,
1105
+ 10247,
1106
+ 10255
1107
+ ].map((code) => String.fromCodePoint(code));
1108
+ CHECK_MARK = String.fromCodePoint(10004);
1109
+ CROSS_MARK = String.fromCodePoint(10006);
1110
+ }
1111
+ });
1112
+
1113
+ // ../utils/src/log.ts
1114
+ var init_log = __esm({
1115
+ "../utils/src/log.ts"() {
1116
+ "use strict";
1117
+ init_ansi();
1118
+ init_spinner();
1119
+ }
1120
+ });
1121
+
1122
+ // ../utils/src/name.ts
1123
+ var init_name = __esm({
1124
+ "../utils/src/name.ts"() {
1125
+ "use strict";
1126
+ }
1127
+ });
1128
+
1129
+ // ../utils/src/string.ts
1130
+ function pluralize(count, singular, plural) {
1131
+ return count === 1 ? singular : plural || `${singular}s`;
1132
+ }
1133
+ var init_string = __esm({
1134
+ "../utils/src/string.ts"() {
1135
+ "use strict";
1136
+ }
1137
+ });
1138
+
1139
+ // ../utils/src/lifecycle.ts
1140
+ var init_lifecycle = __esm({
1141
+ "../utils/src/lifecycle.ts"() {
1142
+ "use strict";
1143
+ }
1144
+ });
1145
+
1146
+ // ../utils/src/timezone.ts
1147
+ var init_timezone = __esm({
1148
+ "../utils/src/timezone.ts"() {
1149
+ "use strict";
1150
+ }
1151
+ });
1152
+
1153
+ // ../utils/src/slug.ts
1154
+ var init_slug = __esm({
1155
+ "../utils/src/slug.ts"() {
1156
+ "use strict";
1157
+ }
1158
+ });
942
1159
 
943
1160
  // ../utils/src/pure/index.ts
944
- init_package_json();
1161
+ var init_pure = __esm({
1162
+ "../utils/src/pure/index.ts"() {
1163
+ "use strict";
1164
+ init_uuid();
1165
+ init_mime();
1166
+ init_log();
1167
+ init_name();
1168
+ init_string();
1169
+ init_lifecycle();
1170
+ init_timezone();
1171
+ init_package_json();
1172
+ init_slug();
1173
+ }
1174
+ });
1175
+
1176
+ // ../utils/src/index.ts
1177
+ var init_src2 = __esm({
1178
+ "../utils/src/index.ts"() {
1179
+ "use strict";
1180
+ init_pure();
1181
+ }
1182
+ });
1183
+
1184
+ // src/lib/config/timeback-derive.ts
1185
+ var init_timeback_derive = __esm({
1186
+ "src/lib/config/timeback-derive.ts"() {
1187
+ "use strict";
1188
+ init_game();
1189
+ }
1190
+ });
945
1191
 
946
1192
  // src/lib/templates/loader.ts
947
1193
  import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
948
1194
  import { dirname as dirname3, resolve as resolve3 } from "path";
949
1195
  import { fileURLToPath } from "url";
950
- var currentDir = dirname3(fileURLToPath(import.meta.url));
951
1196
  function loadTemplateString(filename) {
952
1197
  const filenamesToTry = filename.endsWith(".template") ? [filename] : [filename, `${filename}.template`];
953
1198
  const candidatePaths = filenamesToTry.flatMap((name) => [
@@ -963,6 +1208,49 @@ function loadTemplateString(filename) {
963
1208
  }
964
1209
  throw new Error(`Template not found: ${filename}. Searched: ${candidatePaths.join(", ")}`);
965
1210
  }
1211
+ var currentDir;
1212
+ var init_loader2 = __esm({
1213
+ "src/lib/templates/loader.ts"() {
1214
+ "use strict";
1215
+ currentDir = dirname3(fileURLToPath(import.meta.url));
1216
+ }
1217
+ });
1218
+
1219
+ // src/lib/config/generator.ts
1220
+ var init_generator = __esm({
1221
+ "src/lib/config/generator.ts"() {
1222
+ "use strict";
1223
+ init_loader2();
1224
+ }
1225
+ });
1226
+
1227
+ // src/lib/config/writer.ts
1228
+ var init_writer = __esm({
1229
+ "src/lib/config/writer.ts"() {
1230
+ "use strict";
1231
+ }
1232
+ });
1233
+
1234
+ // src/lib/config/index.ts
1235
+ var init_config3 = __esm({
1236
+ "src/lib/config/index.ts"() {
1237
+ "use strict";
1238
+ init_loader();
1239
+ init_timeback_derive();
1240
+ init_generator();
1241
+ init_writer();
1242
+ }
1243
+ });
1244
+
1245
+ // src/lib/core/game.ts
1246
+ var init_game = __esm({
1247
+ "src/lib/core/game.ts"() {
1248
+ "use strict";
1249
+ init_src2();
1250
+ init_slug();
1251
+ init_config3();
1252
+ }
1253
+ });
966
1254
 
967
1255
  // src/lib/core/import.ts
968
1256
  import { mkdtempSync, rmSync } from "fs";
@@ -998,13 +1286,135 @@ async function importTypescriptDefault(filePath, bundleOptions) {
998
1286
  }
999
1287
  return module;
1000
1288
  }
1289
+ var init_import = __esm({
1290
+ "src/lib/core/import.ts"() {
1291
+ "use strict";
1292
+ }
1293
+ });
1294
+
1295
+ // src/lib/core/index.ts
1296
+ var init_core = __esm({
1297
+ "src/lib/core/index.ts"() {
1298
+ "use strict";
1299
+ init_client();
1300
+ init_config2();
1301
+ init_context();
1302
+ init_errors();
1303
+ init_game();
1304
+ init_import();
1305
+ init_logger();
1306
+ }
1307
+ });
1308
+
1309
+ // src/utils.ts
1310
+ init_loader();
1311
+ init_loader();
1312
+ init_loader();
1313
+
1314
+ // src/lib/dev/server.ts
1315
+ init_src();
1316
+ import { mkdir as mkdir2 } from "fs/promises";
1317
+ import { join as join12 } from "path";
1318
+ import { Log, LogLevel, Miniflare } from "miniflare";
1319
+
1320
+ // ../utils/src/port.ts
1321
+ import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "node:fs";
1322
+ import { createServer } from "node:net";
1323
+ import { homedir } from "node:os";
1324
+ import { join as join2 } from "node:path";
1325
+ async function isPortAvailableOnHost(port, host) {
1326
+ return new Promise((resolve4) => {
1327
+ const server = createServer();
1328
+ let resolved = false;
1329
+ const cleanup = (result) => {
1330
+ if (resolved) return;
1331
+ resolved = true;
1332
+ try {
1333
+ server.close();
1334
+ } catch {
1335
+ }
1336
+ resolve4(result);
1337
+ };
1338
+ const timeout = setTimeout(() => cleanup(true), 100);
1339
+ server.once("error", (err) => {
1340
+ clearTimeout(timeout);
1341
+ if (err.code === "EAFNOSUPPORT" || err.code === "EADDRNOTAVAIL") {
1342
+ cleanup(true);
1343
+ } else {
1344
+ cleanup(false);
1345
+ }
1346
+ });
1347
+ server.once("listening", () => {
1348
+ clearTimeout(timeout);
1349
+ cleanup(true);
1350
+ });
1351
+ server.listen(port, host).unref();
1352
+ });
1353
+ }
1354
+ async function findAvailablePort(startPort = 4321) {
1355
+ if (await isPortAvailableOnHost(startPort, "0.0.0.0")) {
1356
+ return startPort;
1357
+ } else {
1358
+ return findAvailablePort(startPort + 1);
1359
+ }
1360
+ }
1361
+ function getRegistryPath() {
1362
+ const home = homedir();
1363
+ const dir = join2(home, ".playcademy");
1364
+ if (!existsSync2(dir)) {
1365
+ mkdirSync(dir, { recursive: true });
1366
+ }
1367
+ return join2(dir, ".proc");
1368
+ }
1369
+ function readRegistry() {
1370
+ const registryPath = getRegistryPath();
1371
+ if (!existsSync2(registryPath)) {
1372
+ return {};
1373
+ }
1374
+ try {
1375
+ const content = readFileSync(registryPath, "utf-8");
1376
+ return JSON.parse(content);
1377
+ } catch {
1378
+ return {};
1379
+ }
1380
+ }
1381
+ function writeRegistry(registry) {
1382
+ const registryPath = getRegistryPath();
1383
+ writeFileSync(registryPath, JSON.stringify(registry, null, 2), "utf-8");
1384
+ }
1385
+ function getServerKey(type, port) {
1386
+ return `${type}-${port}`;
1387
+ }
1388
+ function writeServerInfo(type, info) {
1389
+ const registry = readRegistry();
1390
+ const key = getServerKey(type, info.port);
1391
+ registry[key] = info;
1392
+ writeRegistry(registry);
1393
+ }
1394
+ function readServerInfo(type, projectRoot) {
1395
+ const registry = readRegistry();
1396
+ const servers = Object.entries(registry).filter(([key]) => key.startsWith(`${type}-`)).map(([, info]) => info);
1397
+ if (servers.length === 0) {
1398
+ return null;
1399
+ }
1400
+ if (projectRoot) {
1401
+ const match = servers.find((s) => s.projectRoot === projectRoot);
1402
+ return match || null;
1403
+ }
1404
+ return servers[0] || null;
1405
+ }
1406
+
1407
+ // src/lib/dev/server.ts
1408
+ init_constants2();
1409
+ init_loader();
1410
+ init_core();
1001
1411
 
1002
1412
  // src/lib/deploy/bundle.ts
1003
1413
  import { existsSync as existsSync5 } from "fs";
1004
1414
  import { join as join6 } from "path";
1005
1415
 
1006
1416
  // ../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";
1417
+ 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
1418
 
1009
1419
  // ../utils/src/path.ts
1010
1420
  import fs from "node:fs";
@@ -1220,6 +1630,9 @@ function getMonorepoRoot() {
1220
1630
  return memoizedRoot;
1221
1631
  }
1222
1632
 
1633
+ // src/lib/deploy/bundle.ts
1634
+ init_constants2();
1635
+
1223
1636
  // src/lib/build/plugins.ts
1224
1637
  function textLoaderPlugin() {
1225
1638
  return {
@@ -1253,8 +1666,12 @@ function textLoaderPlugin() {
1253
1666
  };
1254
1667
  }
1255
1668
 
1669
+ // src/lib/deploy/bundle.ts
1670
+ init_core();
1671
+
1256
1672
  // src/lib/dev/routes.ts
1257
1673
  init_file_loader();
1674
+ init_core();
1258
1675
  import { mkdir, writeFile } from "fs/promises";
1259
1676
  import { tmpdir as tmpdir2 } from "os";
1260
1677
  import { join as join5, relative } from "path";
@@ -1310,6 +1727,7 @@ function filePathToRoutePath(filePath) {
1310
1727
  routePath = routePath.replace(/\/?index$/, "");
1311
1728
  }
1312
1729
  let urlPath = "/" + routePath.replace(/\\/g, "/");
1730
+ urlPath = urlPath.replace(/\[\.\.\.([^\]]+)\]/g, ":$1{.*}");
1313
1731
  urlPath = urlPath.replace(/\[([^\]]+)\]/g, ":$1");
1314
1732
  urlPath = urlPath === "/" ? "/api" : `/api${urlPath}`;
1315
1733
  return urlPath;
@@ -1454,7 +1872,7 @@ async function bundleBackend(config, options = {}) {
1454
1872
  const { customRouteData, customRoutesDir } = await discoverCustomRoutes(config);
1455
1873
  const bundleConfig = {
1456
1874
  ...config,
1457
- customRoutes: customRouteData
1875
+ __routeMetadata: customRouteData
1458
1876
  };
1459
1877
  const entryCode = generateEntryCode(customRouteData, customRoutesDir);
1460
1878
  const paths = resolveEmbeddedSourcePaths();
@@ -1504,8 +1922,19 @@ function generateEntryCode(customRoutes, customRoutesDir) {
1504
1922
  // src/lib/init/prompts.ts
1505
1923
  import { checkbox, confirm, input, select } from "@inquirer/prompts";
1506
1924
  import { bold as bold3, cyan as cyan2 } from "colorette";
1925
+ init_constants2();
1926
+
1927
+ // src/lib/init/scaffold.ts
1928
+ init_constants2();
1929
+ init_core();
1930
+ init_loader2();
1507
1931
 
1508
1932
  // src/lib/init/database.ts
1933
+ init_log();
1934
+ init_slug();
1935
+ init_core();
1936
+ init_logger();
1937
+ init_loader2();
1509
1938
  import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
1510
1939
  import { join as join7 } from "path";
1511
1940
  var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
@@ -1530,7 +1959,9 @@ var sampleBucketRouteTemplate = loadTemplateString("api/sample-bucket.ts");
1530
1959
  var playcademyGitignoreTemplate = loadTemplateString("playcademy-gitignore");
1531
1960
 
1532
1961
  // src/lib/init/display.ts
1533
- import { blueBright } from "colorette";
1962
+ init_package_manager();
1963
+ init_context();
1964
+ init_logger();
1534
1965
 
1535
1966
  // src/lib/init/kv.ts
1536
1967
  function hasKVSetup(config) {
@@ -1544,57 +1975,292 @@ function hasBucketSetup(config) {
1544
1975
 
1545
1976
  // src/lib/init/types.ts
1546
1977
  init_file_loader();
1978
+ init_package_manager();
1979
+ init_string();
1980
+ init_constants2();
1981
+ init_loader();
1982
+ init_core();
1547
1983
  import { execSync as execSync2 } from "child_process";
1548
- import { writeFileSync as writeFileSync3 } from "fs";
1549
- import { dirname as dirname4, join as join8 } from "path";
1984
+ import { writeFileSync as writeFileSync4 } from "fs";
1985
+ import { dirname as dirname4, join as join11 } from "path";
1550
1986
  import { fileURLToPath as fileURLToPath2 } from "url";
1987
+
1988
+ // src/lib/deploy/backend.ts
1989
+ init_src2();
1990
+ init_constants2();
1991
+ init_core();
1992
+ import { existsSync as existsSync7 } from "node:fs";
1993
+ import { join as join8 } from "node:path";
1994
+
1995
+ // src/lib/integrations/timeback.ts
1996
+ init_src2();
1997
+ init_core();
1998
+
1999
+ // src/lib/integrations/utils.ts
2000
+ init_string();
2001
+
2002
+ // src/lib/deploy/schema.ts
2003
+ init_core();
2004
+
2005
+ // src/lib/deploy/secrets.ts
2006
+ init_core();
2007
+ init_logger();
2008
+
2009
+ // src/lib/deploy/utils.ts
2010
+ init_src();
2011
+
2012
+ // src/lib/deploy/backend.ts
2013
+ function getCustomRoutesDirectory(projectPath, config) {
2014
+ const customRoutes = config?.integrations?.customRoutes;
2015
+ const customRoutesDir = typeof customRoutes === "object" && customRoutes.directory || DEFAULT_API_ROUTES_DIRECTORY;
2016
+ return join8(projectPath, customRoutesDir);
2017
+ }
2018
+ function hasLocalCustomRoutes(projectPath, config) {
2019
+ const customRoutesDir = getCustomRoutesDirectory(projectPath, config);
2020
+ return existsSync7(customRoutesDir);
2021
+ }
2022
+
2023
+ // src/lib/secrets/env.ts
2024
+ init_file_loader();
2025
+ init_constants2();
2026
+ import { existsSync as existsSync8 } from "fs";
2027
+ import { join as join9 } from "path";
2028
+ function parseEnvFile(contents) {
2029
+ const secrets = {};
2030
+ for (const line of contents.split("\n")) {
2031
+ const trimmed = line.trim();
2032
+ if (!trimmed || trimmed.startsWith("#")) {
2033
+ continue;
2034
+ }
2035
+ const match = trimmed.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
2036
+ if (match) {
2037
+ const [, key, value] = match;
2038
+ if (!key || !value) {
2039
+ continue;
2040
+ }
2041
+ const unquoted = value.replace(/^["']|["']$/g, "");
2042
+ secrets[key] = unquoted;
2043
+ }
2044
+ }
2045
+ return secrets;
2046
+ }
2047
+ async function readEnvFile(workspace) {
2048
+ let secrets = {};
2049
+ for (const filename of ENV_FILES) {
2050
+ try {
2051
+ const contents = await loadFile(filename, { cwd: workspace, searchUp: false });
2052
+ if (contents) {
2053
+ const fileSecrets = parseEnvFile(contents);
2054
+ secrets = { ...secrets, ...fileSecrets };
2055
+ }
2056
+ } catch {
2057
+ continue;
2058
+ }
2059
+ }
2060
+ return secrets;
2061
+ }
2062
+ function getLoadedEnvFiles(workspace) {
2063
+ return ENV_FILES.filter((filename) => existsSync8(join9(workspace, filename)));
2064
+ }
2065
+ function hasEnvFile(workspace) {
2066
+ return ENV_FILES.some((filename) => existsSync8(join9(workspace, filename)));
2067
+ }
2068
+
2069
+ // src/lib/init/types.ts
2070
+ init_loader2();
2071
+
2072
+ // src/lib/init/tsconfig.ts
2073
+ init_file_loader();
2074
+ init_constants2();
2075
+ import { existsSync as existsSync9, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
2076
+ import { join as join10 } from "path";
2077
+ function hasPlaycademyEnv(config) {
2078
+ return config.include?.includes("playcademy-env.d.ts") ?? false;
2079
+ }
2080
+ function addPlaycademyEnv(config) {
2081
+ if (!config.include) {
2082
+ config.include = [];
2083
+ }
2084
+ config.include.push("playcademy-env.d.ts");
2085
+ }
2086
+ function updateExistingIncludeArray(content) {
2087
+ const includeRegex = /"include"\s*:\s*\[([^\]]*)\]/;
2088
+ const match = content.match(includeRegex);
2089
+ if (!match || !match[1]) {
2090
+ return null;
2091
+ }
2092
+ const fullMatch = match[0];
2093
+ const arrayContents = match[1];
2094
+ if (arrayContents.includes("playcademy-env.d.ts")) {
2095
+ return content;
2096
+ }
2097
+ const trimmedContents = arrayContents.trim();
2098
+ const newEntry = '"playcademy-env.d.ts"';
2099
+ let newArrayContents;
2100
+ if (trimmedContents === "") {
2101
+ newArrayContents = newEntry;
2102
+ } else if (arrayContents.includes("\n")) {
2103
+ newArrayContents = `${arrayContents},
2104
+ ${newEntry}
2105
+ `;
2106
+ } else {
2107
+ newArrayContents = `${trimmedContents}, ${newEntry}`;
2108
+ }
2109
+ const newIncludeArray = `"include": [${newArrayContents}]`;
2110
+ return content.replace(fullMatch, newIncludeArray);
2111
+ }
2112
+ function addNewIncludeProperty(content) {
2113
+ const closingBraceMatch = content.match(/\n(\s*)\}(\s*)$/);
2114
+ if (!closingBraceMatch || closingBraceMatch.index === void 0) {
2115
+ return null;
2116
+ }
2117
+ const propertyMatch = content.match(/\n(\s+)"/);
2118
+ const propertyIndent = propertyMatch ? propertyMatch[1] : " ";
2119
+ const insertPosition = closingBraceMatch.index;
2120
+ const beforeClosing = content.slice(0, insertPosition).trim();
2121
+ const needsComma = beforeClosing.endsWith("]") || beforeClosing.endsWith("}") || beforeClosing.endsWith('"');
2122
+ const comma = needsComma ? "," : "";
2123
+ const includeEntry = `${comma}
2124
+ ${propertyIndent}"include": ["playcademy-env.d.ts"]`;
2125
+ const updatedContent = content.slice(0, insertPosition) + includeEntry + content.slice(insertPosition);
2126
+ return updatedContent;
2127
+ }
2128
+ function addToIncludeArrayPreservingComments(content) {
2129
+ return updateExistingIncludeArray(content) || addNewIncludeProperty(content);
2130
+ }
2131
+ async function ensureTsconfigIncludes(workspace) {
2132
+ for (const filename of TSCONFIG_FILES) {
2133
+ const configPath = join10(workspace, filename);
2134
+ if (!existsSync9(configPath)) {
2135
+ continue;
2136
+ }
2137
+ try {
2138
+ const config = await loadFile(configPath, {
2139
+ parseJson: true,
2140
+ stripComments: true
2141
+ });
2142
+ if (!config) continue;
2143
+ if (config.references && filename !== "tsconfig.json") {
2144
+ continue;
2145
+ }
2146
+ if (hasPlaycademyEnv(config)) {
2147
+ return filename;
2148
+ }
2149
+ try {
2150
+ const rawContent = readFileSync4(configPath, "utf-8");
2151
+ const updatedContent = addToIncludeArrayPreservingComments(rawContent);
2152
+ if (updatedContent && updatedContent !== rawContent) {
2153
+ writeFileSync3(configPath, updatedContent);
2154
+ return filename;
2155
+ }
2156
+ } catch {
2157
+ }
2158
+ addPlaycademyEnv(config);
2159
+ writeFileSync3(configPath, JSON.stringify(config, null, 4) + "\n");
2160
+ return filename;
2161
+ } catch {
2162
+ continue;
2163
+ }
2164
+ }
2165
+ return null;
2166
+ }
2167
+
2168
+ // src/lib/init/types.ts
1551
2169
  var playcademyEnvTemplate = loadTemplateString("playcademy-env.d.ts");
1552
- async function ensurePlaycademyTypes() {
2170
+ function detectBackendFeatures(workspace, config) {
2171
+ return {
2172
+ hasDB: hasDatabaseSetup(),
2173
+ hasKV: hasKVSetup(config),
2174
+ hasBucket: hasBucketSetup(config),
2175
+ hasRoutes: hasLocalCustomRoutes(workspace, config),
2176
+ hasSecrets: hasEnvFile(workspace)
2177
+ };
2178
+ }
2179
+ function hasAnyBackend(features) {
2180
+ return Object.values(features).some(Boolean);
2181
+ }
2182
+ async function setupPlaycademyDependencies(workspace) {
2183
+ const playcademyDir = join11(workspace, CLI_DIRECTORIES.WORKSPACE);
2184
+ const playcademyPkgPath = join11(playcademyDir, "package.json");
2185
+ const __dirname = dirname4(fileURLToPath2(import.meta.url));
2186
+ const cliPkg = await loadPackageJson({ cwd: __dirname, searchUp: true, required: true });
2187
+ const workersTypesVersion = cliPkg?.devDependencies?.["@cloudflare/workers-types"] || "latest";
2188
+ const honoVersion = cliPkg?.dependencies?.hono || "latest";
2189
+ const playcademyPkg = {
2190
+ private: true,
2191
+ dependencies: { hono: honoVersion },
2192
+ devDependencies: { "@cloudflare/workers-types": workersTypesVersion }
2193
+ };
2194
+ writeFileSync4(playcademyPkgPath, JSON.stringify(playcademyPkg, null, 4) + "\n");
2195
+ const pm = detectPackageManager(workspace);
2196
+ const installCmd = getInstallCommand(pm);
2197
+ execSync2(installCmd, {
2198
+ cwd: playcademyDir,
2199
+ stdio: ["ignore", "ignore", "ignore"]
2200
+ });
2201
+ }
2202
+ function generateBindingsTypeString(features) {
2203
+ const bindings = [];
2204
+ if (features.hasKV) bindings.push(" KV: KVNamespace");
2205
+ if (features.hasDB) bindings.push(" DB: D1Database");
2206
+ if (features.hasBucket) bindings.push(" BUCKET: R2Bucket");
2207
+ return bindings.length > 0 ? "\n" + bindings.join("\n") : "";
2208
+ }
2209
+ async function generateSecretsTypeString(workspace, verbose = false) {
2210
+ try {
2211
+ const envSecrets = await readEnvFile(workspace);
2212
+ const secretKeys = Object.keys(envSecrets);
2213
+ if (secretKeys.length === 0) {
2214
+ if (verbose) logger.success("No secrets in <.env> files");
2215
+ return "\n secrets: Record<string, string>";
2216
+ }
2217
+ if (verbose) {
2218
+ const loadedFiles = getLoadedEnvFiles(workspace);
2219
+ const fileList = loadedFiles.map((f) => `<${f}>`).join(", ");
2220
+ logger.success(
2221
+ `Loaded ${secretKeys.length} ${pluralize(secretKeys.length, "secret")} from ${fileList}`
2222
+ );
2223
+ }
2224
+ const secretTypes = secretKeys.map((key) => ` ${key}: string`).join("\n");
2225
+ return `
2226
+ secrets: {
2227
+ ${secretTypes}
2228
+ [key: string]: string
2229
+ }`;
2230
+ } catch {
2231
+ return "\n secrets: Record<string, string>";
2232
+ }
2233
+ }
2234
+ async function ensurePlaycademyTypes(options = {}) {
2235
+ const { verbose = false } = options;
1553
2236
  try {
1554
2237
  const workspace = getWorkspace();
1555
2238
  const config = await loadConfig();
1556
- const hasDB = hasDatabaseSetup();
1557
- const hasKV = hasKVSetup(config);
1558
- const hasBucket = hasBucketSetup(config);
1559
- if (!hasDB && !hasKV && !hasBucket) {
2239
+ const features = detectBackendFeatures(workspace, config);
2240
+ if (!hasAnyBackend(features)) {
2241
+ if (verbose) {
2242
+ logger.dim("No backend functionality detected");
2243
+ }
1560
2244
  return;
1561
2245
  }
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");
2246
+ await setupPlaycademyDependencies(workspace);
2247
+ if (verbose) {
2248
+ logger.success(`Installed packages in <${CLI_DIRECTORIES.WORKSPACE}>`);
1587
2249
  }
1588
- if (hasDB) {
1589
- bindings.push(" DB: D1Database");
2250
+ const bindingsStr = generateBindingsTypeString(features);
2251
+ const secretsStr = await generateSecretsTypeString(workspace, verbose);
2252
+ let envContent = playcademyEnvTemplate.replace("{{BINDINGS}}", bindingsStr);
2253
+ envContent = envContent.replace("{{SECRETS}}", secretsStr);
2254
+ const envPath = join11(workspace, "playcademy-env.d.ts");
2255
+ writeFileSync4(envPath, envContent);
2256
+ if (verbose) {
2257
+ logger.success(`Generated <playcademy-env.d.ts>`);
1590
2258
  }
1591
- if (hasBucket) {
1592
- bindings.push(" BUCKET: R2Bucket");
2259
+ const tsConfigFilename = await ensureTsconfigIncludes(workspace);
2260
+ if (verbose) {
2261
+ logger.success(`Updated <${tsConfigFilename}>`);
1593
2262
  }
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);
2263
+ logger.newLine();
1598
2264
  } catch (error) {
1599
2265
  logger.warn(
1600
2266
  `Failed to generate TypeScript types: ${error instanceof Error ? error.message : String(error)}`
@@ -1603,6 +2269,8 @@ async function ensurePlaycademyTypes() {
1603
2269
  }
1604
2270
 
1605
2271
  // src/lib/init/gitignore.ts
2272
+ init_core();
2273
+ init_loader2();
1606
2274
  var rootGitignoreTemplate = loadTemplateString("gitignore");
1607
2275
 
1608
2276
  // src/lib/dev/server.ts
@@ -1629,9 +2297,19 @@ async function startDevServer(options) {
1629
2297
  const kvDir = hasKV ? await ensureKvDirectory() : void 0;
1630
2298
  const hasBucket = hasBucketSetup(config);
1631
2299
  const bucketDir = hasBucket ? await ensureBucketDirectory() : void 0;
2300
+ const workspace = getWorkspace();
2301
+ const envSecrets = await readEnvFile(workspace);
1632
2302
  const log2 = logger2 ? new FilteredLog(LogLevel.INFO) : new Log(LogLevel.NONE);
1633
- const sandboxInfo = readServerInfo("sandbox", getWorkspace());
2303
+ const sandboxInfo = readServerInfo("sandbox", workspace);
1634
2304
  const baseUrl = platformUrl ?? sandboxInfo?.url ?? process.env.PLAYCADEMY_BASE_URL ?? `http://localhost:${DEFAULT_PORTS.SANDBOX}`;
2305
+ const bindings = {
2306
+ PLAYCADEMY_API_KEY: process.env.PLAYCADEMY_API_KEY || "dev-api-key",
2307
+ GAME_ID: CORE_GAME_UUIDS.PLAYGROUND,
2308
+ PLAYCADEMY_BASE_URL: baseUrl
2309
+ };
2310
+ for (const [key, value] of Object.entries(envSecrets)) {
2311
+ bindings[`secrets_${key}`] = value;
2312
+ }
1635
2313
  const mf = new Miniflare({
1636
2314
  port,
1637
2315
  log: log2,
@@ -1642,11 +2320,7 @@ async function startDevServer(options) {
1642
2320
  contents: bundle.code
1643
2321
  }
1644
2322
  ],
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
- },
2323
+ bindings,
1650
2324
  d1Databases: hasDatabase ? ["DB"] : [],
1651
2325
  d1Persist: dbDir,
1652
2326
  kvNamespaces: hasKV ? ["KV"] : [],
@@ -1662,7 +2336,7 @@ async function startDevServer(options) {
1662
2336
  return { server: mf, port };
1663
2337
  }
1664
2338
  async function ensureDatabaseDirectory() {
1665
- const dbDir = join9(getWorkspace(), CLI_DIRECTORIES.DATABASE);
2339
+ const dbDir = join12(getWorkspace(), CLI_DIRECTORIES.DATABASE);
1666
2340
  try {
1667
2341
  await mkdir2(dbDir, { recursive: true });
1668
2342
  } catch (error) {
@@ -1671,7 +2345,7 @@ async function ensureDatabaseDirectory() {
1671
2345
  return dbDir;
1672
2346
  }
1673
2347
  async function ensureKvDirectory() {
1674
- const kvDir = join9(getWorkspace(), CLI_DIRECTORIES.KV);
2348
+ const kvDir = join12(getWorkspace(), CLI_DIRECTORIES.KV);
1675
2349
  try {
1676
2350
  await mkdir2(kvDir, { recursive: true });
1677
2351
  } catch (error) {
@@ -1680,7 +2354,7 @@ async function ensureKvDirectory() {
1680
2354
  return kvDir;
1681
2355
  }
1682
2356
  async function ensureBucketDirectory() {
1683
- const bucketDir = join9(getWorkspace(), CLI_DIRECTORIES.BUCKET);
2357
+ const bucketDir = join12(getWorkspace(), CLI_DIRECTORIES.BUCKET);
1684
2358
  try {
1685
2359
  await mkdir2(bucketDir, { recursive: true });
1686
2360
  } catch (error) {
@@ -1703,7 +2377,9 @@ async function writeBackendServerInfo(port) {
1703
2377
  }
1704
2378
 
1705
2379
  // src/lib/dev/reload.ts
1706
- import { join as join10, relative as relative2 } from "path";
2380
+ init_constants2();
2381
+ init_core();
2382
+ import { join as join13, relative as relative2 } from "path";
1707
2383
  import chokidar from "chokidar";
1708
2384
  import { bold as bold4, cyan as cyan3, dim as dim3, green as green2 } from "colorette";
1709
2385
  function formatTime() {
@@ -1720,9 +2396,9 @@ function startHotReload(onReload, options = {}) {
1720
2396
  const customRoutesConfig = options.config?.integrations?.customRoutes;
1721
2397
  const customRoutesDir = typeof customRoutesConfig === "object" && customRoutesConfig.directory || DEFAULT_API_ROUTES_DIRECTORY;
1722
2398
  const watchPaths = [
1723
- join10(workspace, customRoutesDir),
1724
- join10(workspace, "playcademy.config.js"),
1725
- join10(workspace, "playcademy.config.json")
2399
+ join13(workspace, customRoutesDir),
2400
+ join13(workspace, "playcademy.config.js"),
2401
+ join13(workspace, "playcademy.config.json")
1726
2402
  ];
1727
2403
  const watcher = chokidar.watch(watchPaths, {
1728
2404
  persistent: true,
@@ -1760,6 +2436,9 @@ function startHotReload(onReload, options = {}) {
1760
2436
  watcher.on("unlink", createReloadHandler("removed"));
1761
2437
  return watcher;
1762
2438
  }
2439
+
2440
+ // src/utils.ts
2441
+ init_import();
1763
2442
  export {
1764
2443
  findConfigPath as findPlaycademyConfigPath,
1765
2444
  importTypescriptDefault,