playcademy 0.14.24 → 0.14.26

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.
@@ -30,3 +30,69 @@ export const TIMEBACK_ROUTES = {
30
30
  * This is the default organization sourcedId for Playcademy games
31
31
  */
32
32
  export const TIMEBACK_ORG_SOURCED_ID = 'PLAYCADEMY' as const
33
+
34
+ /**
35
+ * Default organization name for Playcademy games
36
+ */
37
+ export const TIMEBACK_ORG_NAME = 'Playcademy Studios' as const
38
+
39
+ /**
40
+ * Default organization type for Playcademy games
41
+ */
42
+ export const TIMEBACK_ORG_TYPE = 'department' as const
43
+
44
+ // ============================================================================
45
+ // TimeBack Resource Defaults
46
+ // ============================================================================
47
+
48
+ /**
49
+ * Default course configuration values
50
+ */
51
+ export const TIMEBACK_COURSE_DEFAULTS = {
52
+ gradingScheme: 'STANDARD',
53
+ level: {
54
+ elementary: 'Elementary',
55
+ middle: 'Middle',
56
+ high: 'High',
57
+ ap: 'AP',
58
+ },
59
+ goals: {
60
+ dailyXp: 50,
61
+ dailyLessons: 3,
62
+ },
63
+ metrics: {
64
+ totalXp: 1000,
65
+ totalLessons: 50,
66
+ },
67
+ } as const
68
+
69
+ /**
70
+ * Default resource configuration values
71
+ */
72
+ export const TIMEBACK_RESOURCE_DEFAULTS = {
73
+ vendorId: 'playcademy',
74
+ roles: ['primary'] as const,
75
+ importance: 'primary' as const,
76
+ metadata: {
77
+ type: 'interactive' as const,
78
+ toolProvider: 'Playcademy',
79
+ instructionalMethod: 'exploratory' as const,
80
+ language: 'en-US',
81
+ },
82
+ } as const
83
+
84
+ /**
85
+ * Default component configuration values
86
+ */
87
+ export const TIMEBACK_COMPONENT_DEFAULTS = {
88
+ sortOrder: 1,
89
+ prerequisiteCriteria: 'ALL' as const,
90
+ } as const
91
+
92
+ /**
93
+ * Default componentResource configuration values
94
+ */
95
+ export const TIMEBACK_COMPONENT_RESOURCE_DEFAULTS = {
96
+ sortOrder: 1,
97
+ lessonType: 'quiz',
98
+ } as const
package/dist/index.js CHANGED
@@ -3675,7 +3675,6 @@ var TIMEBACK_ENV_VARS = [
3675
3675
  "TIMEBACK_CALIPER_API_URL",
3676
3676
  "SANDBOX_TIMEBACK_STUDENT_ID"
3677
3677
  ];
3678
- var TIMEBACK_COURSE_PATTERN = "SANDBOX_TIMEBACK_COURSE_";
3679
3678
  function maskSecret(value) {
3680
3679
  if (value.length <= 8) {
3681
3680
  return "***";
@@ -3691,9 +3690,6 @@ function getDisplayValue(key, value) {
3691
3690
  function getSetEnvVars(keys) {
3692
3691
  return keys.filter((key) => process.env[key]);
3693
3692
  }
3694
- function getSetEnvVarsByPattern(pattern) {
3695
- return Object.keys(process.env).filter((key) => key.startsWith(pattern)).filter((key) => process.env[key]);
3696
- }
3697
3693
  function printDebugInfo() {
3698
3694
  if (process.env.DEBUG !== "1") {
3699
3695
  return;
@@ -3709,19 +3705,15 @@ function printDebugInfo() {
3709
3705
  }
3710
3706
  }
3711
3707
  const setTimebackVars = getSetEnvVars(TIMEBACK_ENV_VARS);
3712
- const courseKeys = getSetEnvVarsByPattern(TIMEBACK_COURSE_PATTERN);
3713
- if (setTimebackVars.length > 0 || courseKeys.length > 0) {
3708
+ if (setTimebackVars.length > 0) {
3714
3709
  logger.newLine();
3715
3710
  for (const key of setTimebackVars) {
3716
3711
  const value = process.env[key];
3717
3712
  logger.data(key, getDisplayValue(key, value), 1);
3718
3713
  }
3719
- for (const key of courseKeys.sort()) {
3720
- logger.data(key, process.env[key], 1);
3721
- }
3722
3714
  }
3723
3715
  logger.newLine();
3724
- logger.bold("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501END DEBUG OUTPUT\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
3716
+ logger.bold("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501END DEBUG OUTPUT\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
3725
3717
  }
3726
3718
 
3727
3719
  // src/lib/core/errors.ts
@@ -4200,8 +4192,51 @@ var init_overworld2 = __esm2(() => {
4200
4192
  FIRST_GAME: ITEM_SLUGS2.FIRST_GAME_BADGE
4201
4193
  };
4202
4194
  });
4203
- var init_timeback2 = () => {
4204
- };
4195
+ var TIMEBACK_ORG_SOURCED_ID = "PLAYCADEMY";
4196
+ var TIMEBACK_ORG_NAME = "Playcademy Studios";
4197
+ var TIMEBACK_ORG_TYPE = "department";
4198
+ var TIMEBACK_COURSE_DEFAULTS;
4199
+ var TIMEBACK_RESOURCE_DEFAULTS;
4200
+ var TIMEBACK_COMPONENT_DEFAULTS;
4201
+ var TIMEBACK_COMPONENT_RESOURCE_DEFAULTS;
4202
+ var init_timeback2 = __esm2(() => {
4203
+ TIMEBACK_COURSE_DEFAULTS = {
4204
+ gradingScheme: "STANDARD",
4205
+ level: {
4206
+ elementary: "Elementary",
4207
+ middle: "Middle",
4208
+ high: "High",
4209
+ ap: "AP"
4210
+ },
4211
+ goals: {
4212
+ dailyXp: 50,
4213
+ dailyLessons: 3
4214
+ },
4215
+ metrics: {
4216
+ totalXp: 1e3,
4217
+ totalLessons: 50
4218
+ }
4219
+ };
4220
+ TIMEBACK_RESOURCE_DEFAULTS = {
4221
+ vendorId: "playcademy",
4222
+ roles: ["primary"],
4223
+ importance: "primary",
4224
+ metadata: {
4225
+ type: "interactive",
4226
+ toolProvider: "Playcademy",
4227
+ instructionalMethod: "exploratory",
4228
+ language: "en-US"
4229
+ }
4230
+ };
4231
+ TIMEBACK_COMPONENT_DEFAULTS = {
4232
+ sortOrder: 1,
4233
+ prerequisiteCriteria: "ALL"
4234
+ };
4235
+ TIMEBACK_COMPONENT_RESOURCE_DEFAULTS = {
4236
+ sortOrder: 1,
4237
+ lessonType: "quiz"
4238
+ };
4239
+ });
4205
4240
  var init_workers2 = () => {
4206
4241
  };
4207
4242
  var init_src2 = __esm2(() => {
@@ -4234,7 +4269,6 @@ var HTTP_DEFAULTS;
4234
4269
  var AUTH_DEFAULTS;
4235
4270
  var CACHE_DEFAULTS;
4236
4271
  var CONFIG_DEFAULTS;
4237
- var DEFAULT_PLAYCADEMY_ORGANIZATION_ID;
4238
4272
  var PLAYCADEMY_DEFAULTS;
4239
4273
  var RESOURCE_DEFAULTS;
4240
4274
  var HTTP_STATUS;
@@ -4381,54 +4415,26 @@ var init_constants = __esm2(() => {
4381
4415
  CONFIG_DEFAULTS = {
4382
4416
  fileNames: ["timeback.config.js", "timeback.config.json"]
4383
4417
  };
4384
- DEFAULT_PLAYCADEMY_ORGANIZATION_ID = process.env.TIMEBACK_ORG_SOURCE_ID || "PLAYCADEMY";
4385
4418
  PLAYCADEMY_DEFAULTS = {
4386
- organization: DEFAULT_PLAYCADEMY_ORGANIZATION_ID,
4419
+ organization: TIMEBACK_ORG_SOURCED_ID,
4387
4420
  launchBaseUrls: PLAYCADEMY_BASE_URLS2
4388
4421
  };
4389
4422
  RESOURCE_DEFAULTS = {
4390
4423
  organization: {
4391
- name: "Playcademy Studios",
4392
- type: "department"
4424
+ name: TIMEBACK_ORG_NAME,
4425
+ type: TIMEBACK_ORG_TYPE
4393
4426
  },
4394
4427
  course: {
4395
- gradingScheme: "STANDARD",
4396
- level: {
4397
- elementary: "Elementary",
4398
- middle: "Middle",
4399
- high: "High",
4400
- ap: "AP"
4401
- },
4428
+ gradingScheme: TIMEBACK_COURSE_DEFAULTS.gradingScheme,
4429
+ level: TIMEBACK_COURSE_DEFAULTS.level,
4402
4430
  metadata: {
4403
- goals: {
4404
- dailyXp: 50,
4405
- dailyLessons: 3
4406
- },
4407
- metrics: {
4408
- totalXp: 1e3,
4409
- totalLessons: 50
4410
- }
4431
+ goals: TIMEBACK_COURSE_DEFAULTS.goals,
4432
+ metrics: TIMEBACK_COURSE_DEFAULTS.metrics
4411
4433
  }
4412
4434
  },
4413
- component: {
4414
- sortOrder: 1,
4415
- prerequisiteCriteria: "ALL"
4416
- },
4417
- resource: {
4418
- vendorId: "playcademy",
4419
- roles: ["primary"],
4420
- importance: "primary",
4421
- metadata: {
4422
- type: "interactive",
4423
- toolProvider: "Playcademy",
4424
- instructionalMethod: "exploratory",
4425
- language: "en-US"
4426
- }
4427
- },
4428
- componentResource: {
4429
- sortOrder: 1,
4430
- lessonType: "quiz"
4431
- }
4435
+ component: TIMEBACK_COMPONENT_DEFAULTS,
4436
+ resource: TIMEBACK_RESOURCE_DEFAULTS,
4437
+ componentResource: TIMEBACK_COMPONENT_RESOURCE_DEFAULTS
4432
4438
  };
4433
4439
  HTTP_STATUS = {
4434
4440
  CLIENT_ERROR_MIN: 400,
@@ -4484,8 +4490,51 @@ var init_overworld3 = __esm3(() => {
4484
4490
  FIRST_GAME: ITEM_SLUGS3.FIRST_GAME_BADGE
4485
4491
  };
4486
4492
  });
4487
- var init_timeback3 = () => {
4488
- };
4493
+ var TIMEBACK_ORG_SOURCED_ID2 = "PLAYCADEMY";
4494
+ var TIMEBACK_ORG_NAME2 = "Playcademy Studios";
4495
+ var TIMEBACK_ORG_TYPE2 = "department";
4496
+ var TIMEBACK_COURSE_DEFAULTS2;
4497
+ var TIMEBACK_RESOURCE_DEFAULTS2;
4498
+ var TIMEBACK_COMPONENT_DEFAULTS2;
4499
+ var TIMEBACK_COMPONENT_RESOURCE_DEFAULTS2;
4500
+ var init_timeback3 = __esm3(() => {
4501
+ TIMEBACK_COURSE_DEFAULTS2 = {
4502
+ gradingScheme: "STANDARD",
4503
+ level: {
4504
+ elementary: "Elementary",
4505
+ middle: "Middle",
4506
+ high: "High",
4507
+ ap: "AP"
4508
+ },
4509
+ goals: {
4510
+ dailyXp: 50,
4511
+ dailyLessons: 3
4512
+ },
4513
+ metrics: {
4514
+ totalXp: 1e3,
4515
+ totalLessons: 50
4516
+ }
4517
+ };
4518
+ TIMEBACK_RESOURCE_DEFAULTS2 = {
4519
+ vendorId: "playcademy",
4520
+ roles: ["primary"],
4521
+ importance: "primary",
4522
+ metadata: {
4523
+ type: "interactive",
4524
+ toolProvider: "Playcademy",
4525
+ instructionalMethod: "exploratory",
4526
+ language: "en-US"
4527
+ }
4528
+ };
4529
+ TIMEBACK_COMPONENT_DEFAULTS2 = {
4530
+ sortOrder: 1,
4531
+ prerequisiteCriteria: "ALL"
4532
+ };
4533
+ TIMEBACK_COMPONENT_RESOURCE_DEFAULTS2 = {
4534
+ sortOrder: 1,
4535
+ lessonType: "quiz"
4536
+ };
4537
+ });
4489
4538
  var init_workers3 = () => {
4490
4539
  };
4491
4540
  var init_src3 = __esm3(() => {
@@ -4518,7 +4567,6 @@ var HTTP_DEFAULTS2;
4518
4567
  var AUTH_DEFAULTS2;
4519
4568
  var CACHE_DEFAULTS2;
4520
4569
  var CONFIG_DEFAULTS2;
4521
- var DEFAULT_PLAYCADEMY_ORGANIZATION_ID2;
4522
4570
  var PLAYCADEMY_DEFAULTS2;
4523
4571
  var RESOURCE_DEFAULTS2;
4524
4572
  var HTTP_STATUS2;
@@ -4665,54 +4713,26 @@ var init_constants2 = __esm3(() => {
4665
4713
  CONFIG_DEFAULTS2 = {
4666
4714
  fileNames: ["timeback.config.js", "timeback.config.json"]
4667
4715
  };
4668
- DEFAULT_PLAYCADEMY_ORGANIZATION_ID2 = process.env.TIMEBACK_ORG_SOURCE_ID || "PLAYCADEMY";
4669
4716
  PLAYCADEMY_DEFAULTS2 = {
4670
- organization: DEFAULT_PLAYCADEMY_ORGANIZATION_ID2,
4717
+ organization: TIMEBACK_ORG_SOURCED_ID2,
4671
4718
  launchBaseUrls: PLAYCADEMY_BASE_URLS3
4672
4719
  };
4673
4720
  RESOURCE_DEFAULTS2 = {
4674
4721
  organization: {
4675
- name: "Playcademy Studios",
4676
- type: "department"
4722
+ name: TIMEBACK_ORG_NAME2,
4723
+ type: TIMEBACK_ORG_TYPE2
4677
4724
  },
4678
4725
  course: {
4679
- gradingScheme: "STANDARD",
4680
- level: {
4681
- elementary: "Elementary",
4682
- middle: "Middle",
4683
- high: "High",
4684
- ap: "AP"
4685
- },
4686
- metadata: {
4687
- goals: {
4688
- dailyXp: 50,
4689
- dailyLessons: 3
4690
- },
4691
- metrics: {
4692
- totalXp: 1e3,
4693
- totalLessons: 50
4694
- }
4695
- }
4696
- },
4697
- component: {
4698
- sortOrder: 1,
4699
- prerequisiteCriteria: "ALL"
4700
- },
4701
- resource: {
4702
- vendorId: "playcademy",
4703
- roles: ["primary"],
4704
- importance: "primary",
4726
+ gradingScheme: TIMEBACK_COURSE_DEFAULTS2.gradingScheme,
4727
+ level: TIMEBACK_COURSE_DEFAULTS2.level,
4705
4728
  metadata: {
4706
- type: "interactive",
4707
- toolProvider: "Playcademy",
4708
- instructionalMethod: "exploratory",
4709
- language: "en-US"
4729
+ goals: TIMEBACK_COURSE_DEFAULTS2.goals,
4730
+ metrics: TIMEBACK_COURSE_DEFAULTS2.metrics
4710
4731
  }
4711
4732
  },
4712
- componentResource: {
4713
- sortOrder: 1,
4714
- lessonType: "quiz"
4715
- }
4733
+ component: TIMEBACK_COMPONENT_DEFAULTS2,
4734
+ resource: TIMEBACK_RESOURCE_DEFAULTS2,
4735
+ componentResource: TIMEBACK_COMPONENT_RESOURCE_DEFAULTS2
4716
4736
  };
4717
4737
  HTTP_STATUS2 = {
4718
4738
  CLIENT_ERROR_MIN: 400,
@@ -4752,7 +4772,7 @@ function deriveLevelFromGrades(grades) {
4752
4772
  }
4753
4773
  function deriveSourcedIds(courseId) {
4754
4774
  return {
4755
- organization: PLAYCADEMY_DEFAULTS.organization,
4775
+ organization: process.env.TIMEBACK_ORG_SOURCED_ID || PLAYCADEMY_DEFAULTS.organization,
4756
4776
  course: courseId,
4757
4777
  component: `${courseId}-component`,
4758
4778
  resource: `${courseId}-resource`,
@@ -4822,7 +4842,7 @@ function derivePlatformTimebackSetupRequest(config) {
4822
4842
  const defaultOrganization = {
4823
4843
  name: RESOURCE_DEFAULTS.organization.name,
4824
4844
  type: RESOURCE_DEFAULTS.organization.type,
4825
- identifier: PLAYCADEMY_DEFAULTS.organization
4845
+ identifier: process.env.TIMEBACK_ORG_SOURCED_ID || PLAYCADEMY_DEFAULTS.organization
4826
4846
  };
4827
4847
  const defaultComponent = {
4828
4848
  title: "",
@@ -5585,7 +5605,7 @@ import { join as join12 } from "path";
5585
5605
  // package.json
5586
5606
  var package_default2 = {
5587
5607
  name: "playcademy",
5588
- version: "0.14.23",
5608
+ version: "0.14.25",
5589
5609
  type: "module",
5590
5610
  exports: {
5591
5611
  ".": {
@@ -7018,42 +7038,6 @@ import { existsSync as existsSync16, mkdirSync as mkdirSync4, readFileSync as re
7018
7038
  import { createServer } from "node:net";
7019
7039
  import { homedir as homedir3 } from "node:os";
7020
7040
  import { join as join22 } from "node:path";
7021
- async function isPortAvailableOnHost(port, host) {
7022
- return new Promise((resolve11) => {
7023
- const server = createServer();
7024
- let resolved = false;
7025
- const cleanup = (result) => {
7026
- if (resolved) return;
7027
- resolved = true;
7028
- try {
7029
- server.close();
7030
- } catch {
7031
- }
7032
- resolve11(result);
7033
- };
7034
- const timeout = setTimeout(() => cleanup(true), 100);
7035
- server.once("error", (err) => {
7036
- clearTimeout(timeout);
7037
- if (err.code === "EAFNOSUPPORT" || err.code === "EADDRNOTAVAIL") {
7038
- cleanup(true);
7039
- } else {
7040
- cleanup(false);
7041
- }
7042
- });
7043
- server.once("listening", () => {
7044
- clearTimeout(timeout);
7045
- cleanup(true);
7046
- });
7047
- server.listen(port, host).unref();
7048
- });
7049
- }
7050
- async function findAvailablePort(startPort = 4321) {
7051
- if (await isPortAvailableOnHost(startPort, "0.0.0.0")) {
7052
- return startPort;
7053
- } else {
7054
- return findAvailablePort(startPort + 1);
7055
- }
7056
- }
7057
7041
  function getRegistryPath() {
7058
7042
  const home = homedir3();
7059
7043
  const dir = join22(home, ".playcademy");
@@ -7148,6 +7132,31 @@ function cleanupServerInfo(type, projectRoot, pid) {
7148
7132
  writeRegistry(registry);
7149
7133
  }
7150
7134
  }
7135
+ async function isPortInUse(port) {
7136
+ return new Promise((resolve11) => {
7137
+ const server = createServer();
7138
+ server.once("error", () => {
7139
+ resolve11(true);
7140
+ });
7141
+ server.once("listening", () => {
7142
+ server.close();
7143
+ resolve11(false);
7144
+ });
7145
+ server.listen(port);
7146
+ });
7147
+ }
7148
+ async function waitForPort(port, timeoutMs = 5e3) {
7149
+ const start = Date.now();
7150
+ while (await isPortInUse(port)) {
7151
+ if (Date.now() - start > timeoutMs) {
7152
+ throw new Error(
7153
+ `Port ${port} is already in use.
7154
+ Stop the other server or specify a different port with --port <number>.`
7155
+ );
7156
+ }
7157
+ await new Promise((resolve11) => setTimeout(resolve11, 100));
7158
+ }
7159
+ }
7151
7160
 
7152
7161
  // src/lib/deploy/bundle.ts
7153
7162
  import { existsSync as existsSync17 } from "fs";
@@ -7622,15 +7631,9 @@ var FilteredLog = class extends Log {
7622
7631
  }
7623
7632
  };
7624
7633
  async function startDevServer(options) {
7625
- const {
7626
- port: preferredPort,
7627
- config: providedConfig,
7628
- platformUrl,
7629
- logger: logger2 = true,
7630
- customLogger
7631
- } = options;
7632
- const port = await findAvailablePort(preferredPort);
7633
- const config = providedConfig ?? await loadConfig();
7634
+ const { port, config: _config, platformUrl, logger: logger2 = true, customLogger } = options;
7635
+ await waitForPort(port);
7636
+ const config = _config ?? await loadConfig();
7634
7637
  await ensurePlaycademyTypes();
7635
7638
  const hasSandboxTimebackCreds = !!process.env.TIMEBACK_API_CLIENT_ID;
7636
7639
  const devConfig = config.integrations?.timeback && !hasSandboxTimebackCreds ? { ...config, integrations: { ...config.integrations, timeback: null } } : config;
@@ -7646,7 +7649,7 @@ async function startDevServer(options) {
7646
7649
  const bucketDir = hasBucket ? await ensureBucketDirectory() : void 0;
7647
7650
  const workspace = getWorkspace();
7648
7651
  const envSecrets = await readEnvFile(workspace);
7649
- const log2 = logger2 ? new FilteredLog(LogLevel.INFO, customLogger) : new Log(LogLevel.NONE);
7652
+ const filteredLog = logger2 ? new FilteredLog(LogLevel.INFO, customLogger) : new Log(LogLevel.NONE);
7650
7653
  const sandboxInfo = readServerInfo("sandbox", workspace);
7651
7654
  const baseUrl = platformUrl ?? sandboxInfo?.url ?? process.env.PLAYCADEMY_BASE_URL ?? `http://localhost:${DEFAULT_PORTS.SANDBOX}`;
7652
7655
  const bindings = {
@@ -7659,7 +7662,7 @@ async function startDevServer(options) {
7659
7662
  }
7660
7663
  const mf = new Miniflare({
7661
7664
  port,
7662
- log: log2,
7665
+ log: filteredLog,
7663
7666
  modules: [
7664
7667
  {
7665
7668
  type: "ESModule",
@@ -1,7 +1,7 @@
1
1
 
2
2
 
3
3
  // External integrations
4
- // See https://docs.playcademy.net/integrations/overview.html for more details
4
+ // See https://docs.playcademy.net/platform/vite-plugin for more details
5
5
  integrations: {
6
6
  {{INTEGRATIONS_CONTENT}}
7
7
  },
package/dist/utils.js CHANGED
@@ -3214,42 +3214,6 @@ import { existsSync as existsSync3, mkdirSync, readFileSync, writeFileSync } fro
3214
3214
  import { createServer } from "node:net";
3215
3215
  import { homedir } from "node:os";
3216
3216
  import { join as join7 } from "node:path";
3217
- async function isPortAvailableOnHost(port, host) {
3218
- return new Promise((resolve4) => {
3219
- const server = createServer();
3220
- let resolved = false;
3221
- const cleanup = (result) => {
3222
- if (resolved) return;
3223
- resolved = true;
3224
- try {
3225
- server.close();
3226
- } catch {
3227
- }
3228
- resolve4(result);
3229
- };
3230
- const timeout = setTimeout(() => cleanup(true), 100);
3231
- server.once("error", (err) => {
3232
- clearTimeout(timeout);
3233
- if (err.code === "EAFNOSUPPORT" || err.code === "EADDRNOTAVAIL") {
3234
- cleanup(true);
3235
- } else {
3236
- cleanup(false);
3237
- }
3238
- });
3239
- server.once("listening", () => {
3240
- clearTimeout(timeout);
3241
- cleanup(true);
3242
- });
3243
- server.listen(port, host).unref();
3244
- });
3245
- }
3246
- async function findAvailablePort(startPort = 4321) {
3247
- if (await isPortAvailableOnHost(startPort, "0.0.0.0")) {
3248
- return startPort;
3249
- } else {
3250
- return findAvailablePort(startPort + 1);
3251
- }
3252
- }
3253
3217
  function getRegistryPath() {
3254
3218
  const home = homedir();
3255
3219
  const dir = join7(home, ".playcademy");
@@ -3295,6 +3259,31 @@ function readServerInfo(type, projectRoot) {
3295
3259
  }
3296
3260
  return servers[0] || null;
3297
3261
  }
3262
+ async function isPortInUse(port) {
3263
+ return new Promise((resolve4) => {
3264
+ const server = createServer();
3265
+ server.once("error", () => {
3266
+ resolve4(true);
3267
+ });
3268
+ server.once("listening", () => {
3269
+ server.close();
3270
+ resolve4(false);
3271
+ });
3272
+ server.listen(port);
3273
+ });
3274
+ }
3275
+ async function waitForPort(port, timeoutMs = 5e3) {
3276
+ const start = Date.now();
3277
+ while (await isPortInUse(port)) {
3278
+ if (Date.now() - start > timeoutMs) {
3279
+ throw new Error(
3280
+ `Port ${port} is already in use.
3281
+ Stop the other server or specify a different port with --port <number>.`
3282
+ );
3283
+ }
3284
+ await new Promise((resolve4) => setTimeout(resolve4, 100));
3285
+ }
3286
+ }
3298
3287
 
3299
3288
  // src/lib/core/client.ts
3300
3289
  import { PlaycademyClient } from "@playcademy/sdk/internal";
@@ -4003,7 +3992,7 @@ import { join as join12 } from "path";
4003
3992
  // package.json
4004
3993
  var package_default2 = {
4005
3994
  name: "playcademy",
4006
- version: "0.14.23",
3995
+ version: "0.14.25",
4007
3996
  type: "module",
4008
3997
  exports: {
4009
3998
  ".": {
@@ -4386,15 +4375,9 @@ var FilteredLog = class extends Log {
4386
4375
  }
4387
4376
  };
4388
4377
  async function startDevServer(options) {
4389
- const {
4390
- port: preferredPort,
4391
- config: providedConfig,
4392
- platformUrl,
4393
- logger: logger2 = true,
4394
- customLogger
4395
- } = options;
4396
- const port = await findAvailablePort(preferredPort);
4397
- const config = providedConfig ?? await loadConfig();
4378
+ const { port, config: _config, platformUrl, logger: logger2 = true, customLogger } = options;
4379
+ await waitForPort(port);
4380
+ const config = _config ?? await loadConfig();
4398
4381
  await ensurePlaycademyTypes();
4399
4382
  const hasSandboxTimebackCreds = !!process.env.TIMEBACK_API_CLIENT_ID;
4400
4383
  const devConfig = config.integrations?.timeback && !hasSandboxTimebackCreds ? { ...config, integrations: { ...config.integrations, timeback: null } } : config;
@@ -4410,7 +4393,7 @@ async function startDevServer(options) {
4410
4393
  const bucketDir = hasBucket ? await ensureBucketDirectory() : void 0;
4411
4394
  const workspace = getWorkspace();
4412
4395
  const envSecrets = await readEnvFile(workspace);
4413
- const log2 = logger2 ? new FilteredLog(LogLevel.INFO, customLogger) : new Log(LogLevel.NONE);
4396
+ const filteredLog = logger2 ? new FilteredLog(LogLevel.INFO, customLogger) : new Log(LogLevel.NONE);
4414
4397
  const sandboxInfo = readServerInfo("sandbox", workspace);
4415
4398
  const baseUrl = platformUrl ?? sandboxInfo?.url ?? process.env.PLAYCADEMY_BASE_URL ?? `http://localhost:${DEFAULT_PORTS.SANDBOX}`;
4416
4399
  const bindings = {
@@ -4423,7 +4406,7 @@ async function startDevServer(options) {
4423
4406
  }
4424
4407
  const mf = new Miniflare({
4425
4408
  port,
4426
- log: log2,
4409
+ log: filteredLog,
4427
4410
  modules: [
4428
4411
  {
4429
4412
  type: "ESModule",
package/dist/version.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "playcademy",
4
- version: "0.14.23",
4
+ version: "0.14.25",
5
5
  type: "module",
6
6
  exports: {
7
7
  ".": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playcademy",
3
- "version": "0.14.24",
3
+ "version": "0.14.26",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {