@playcademy/sandbox 0.3.4 → 0.3.6

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/README.md CHANGED
@@ -199,17 +199,17 @@ bunx @playcademy/sandbox \
199
199
  --timeback-student-id your-student-sourcedId
200
200
  ```
201
201
 
202
- | Option | Description |
203
- | :------------------------------- | :-------------------------------------------------------- |
204
- | `--timeback-local` | Enable local TimeBack mode (Docker) |
205
- | `--timeback-oneroster-url <url>` | OneRoster API URL |
206
- | `--timeback-caliper-url <url>` | Caliper API URL |
207
- | `--timeback-course-id <id>` | Course ID for enrollments |
208
- | `--timeback-student-id <id>` | Student ID to link to demo user |
209
- | `--timeback-role <role>` | User role (student, parent, teacher, administrator) |
210
- | `--timeback-org-id <id>` | Organization ID |
211
- | `--timeback-org-name <name>` | Organization display name |
212
- | `--timeback-org-type <type>` | Organization type (school, district, department, etc.) |
202
+ | Option | Description |
203
+ | :------------------------------- | :----------------------------------------------------- |
204
+ | `--timeback-local` | Enable local TimeBack mode (Docker) |
205
+ | `--timeback-oneroster-url <url>` | OneRoster API URL |
206
+ | `--timeback-caliper-url <url>` | Caliper API URL |
207
+ | `--timeback-course-id <id>` | Course ID for enrollments |
208
+ | `--timeback-student-id <id>` | Student ID to link to demo user |
209
+ | `--timeback-role <role>` | User role (student, parent, teacher, administrator) |
210
+ | `--timeback-org-id <id>` | Organization ID |
211
+ | `--timeback-org-name <name>` | Organization display name |
212
+ | `--timeback-org-type <type>` | Organization type (school, district, department, etc.) |
213
213
 
214
214
  ### Environment Variables
215
215
 
package/dist/cli.js CHANGED
@@ -120609,6 +120609,9 @@ function configureTimeback(options) {
120609
120609
  config.timeback.role = options.role;
120610
120610
  process.env.SANDBOX_TIMEBACK_ROLE = options.role;
120611
120611
  }
120612
+ if (options.courseOverrides) {
120613
+ config.timeback.courseOverrides = options.courseOverrides;
120614
+ }
120612
120615
  }
120613
120616
  function getTimebackDisplayMode() {
120614
120617
  const { timebackId, mode } = config.timeback;
@@ -121478,7 +121481,7 @@ async function requirePortAvailable(port, timeoutMs = 100) {
121478
121481
  // package.json
121479
121482
  var package_default = {
121480
121483
  name: "@playcademy/sandbox",
121481
- version: "0.3.4",
121484
+ version: "0.3.6",
121482
121485
  description: "Local development server for Playcademy game development",
121483
121486
  type: "module",
121484
121487
  exports: {
@@ -152337,7 +152340,14 @@ function getMockStudentProfile() {
152337
152340
  }
152338
152341
  async function getMockEnrollments(db) {
152339
152342
  const allIntegrations = await db.query.gameTimebackIntegrations.findMany();
152340
- return allIntegrations.map((i4) => ({
152343
+ const overrides = config.timeback.courseOverrides;
152344
+ return allIntegrations.filter((i4) => {
152345
+ if (!overrides)
152346
+ return true;
152347
+ const key = `${i4.subject}:${i4.grade}`;
152348
+ const override = overrides[key];
152349
+ return override !== null && override !== false;
152350
+ }).map((i4) => ({
152341
152351
  gameId: i4.gameId,
152342
152352
  grade: i4.grade,
152343
152353
  subject: i4.subject,
@@ -158314,14 +158324,16 @@ var {
158314
158324
  // src/cli/display.ts
158315
158325
  var import_picocolors = __toESM(require_picocolors(), 1);
158316
158326
  function printBanner(options) {
158317
- const { version: version4, port, startupTimeMs, timebackCourseCount, quiet } = options;
158327
+ const { version: version4, port, startupTimeMs, timebackCourseCount, timebackEnrolledCount, quiet } = options;
158318
158328
  console.log("");
158319
158329
  console.log(` ${import_picocolors.default.green(import_picocolors.default.bold("PLAYCADEMY SANDBOX"))} ${import_picocolors.default.green(`v${version4}`)} ${import_picocolors.default.dim("ready in")} ${import_picocolors.default.bold(startupTimeMs.toString())} ms`);
158320
158330
  console.log("");
158321
- console.log(` ${import_picocolors.default.green("➜")} ${import_picocolors.default.bold("Local:")} ${import_picocolors.default.cyan(`http://localhost:${import_picocolors.default.bold(port.toString())}/api`)}`);
158331
+ console.log(` ${import_picocolors.default.green("➜")} ${import_picocolors.default.bold("Local:")} ${import_picocolors.default.cyan(`http://localhost:${import_picocolors.default.bold(port.toString())}/api`)}`);
158322
158332
  if (timebackCourseCount && timebackCourseCount > 0) {
158323
158333
  const courseText = timebackCourseCount === 1 ? "course" : "courses";
158324
- console.log(` ${import_picocolors.default.green("➜")} ${import_picocolors.default.bold("Timeback:")} ${import_picocolors.default.cyan(`${timebackCourseCount} ${courseText}`)}`);
158334
+ const enrolled = timebackEnrolledCount ?? timebackCourseCount;
158335
+ const enrollmentInfo = enrolled !== timebackCourseCount ? ` / ${enrolled} enrolled` : "";
158336
+ console.log(` ${import_picocolors.default.green("➜")} ${import_picocolors.default.bold("Timeback:")} ${import_picocolors.default.cyan(`${timebackCourseCount} ${courseText}${enrollmentInfo}`)}`);
158325
158337
  }
158326
158338
  console.log("");
158327
158339
  if (!quiet) {
@@ -158530,9 +158542,20 @@ function parseOrganization(options) {
158530
158542
  type: options.timebackOrgType
158531
158543
  };
158532
158544
  }
158545
+ function parseExcludedCourses(excludedCourses) {
158546
+ if (!excludedCourses)
158547
+ return;
158548
+ const overrides = {};
158549
+ const courses = excludedCourses.split(",").map((c3) => c3.trim()).filter(Boolean);
158550
+ for (const course of courses) {
158551
+ overrides[course] = false;
158552
+ }
158553
+ return Object.keys(overrides).length > 0 ? overrides : undefined;
158554
+ }
158533
158555
  function parseTimebackOptions(options) {
158534
158556
  const organization = parseOrganization(options);
158535
158557
  const role = options.timebackRole;
158558
+ const courseOverrides = parseExcludedCourses(options.timebackExcludedCourses);
158536
158559
  if (options.timebackLocal) {
158537
158560
  return {
158538
158561
  mode: "local",
@@ -158541,7 +158564,8 @@ function parseTimebackOptions(options) {
158541
158564
  courseId: options.timebackCourseId,
158542
158565
  timebackId: options.timebackStudentId,
158543
158566
  role,
158544
- organization
158567
+ organization,
158568
+ courseOverrides
158545
158569
  };
158546
158570
  }
158547
158571
  if (options.timebackOnerosterUrl) {
@@ -158552,14 +158576,16 @@ function parseTimebackOptions(options) {
158552
158576
  courseId: options.timebackCourseId,
158553
158577
  timebackId: options.timebackStudentId,
158554
158578
  role,
158555
- organization
158579
+ organization,
158580
+ courseOverrides
158556
158581
  };
158557
158582
  }
158558
- if (role || organization || options.timebackStudentId) {
158583
+ if (role || organization || options.timebackStudentId || courseOverrides) {
158559
158584
  return {
158560
158585
  timebackId: options.timebackStudentId,
158561
158586
  role,
158562
- organization
158587
+ organization,
158588
+ courseOverrides
158563
158589
  };
158564
158590
  }
158565
158591
  return;
@@ -158567,7 +158593,7 @@ function parseTimebackOptions(options) {
158567
158593
 
158568
158594
  // src/cli/index.ts
158569
158595
  var program2 = new Command;
158570
- program2.name("playcademy-sandbox").description("Local development server for Playcademy game development").version(version3).option("-p, --port <number>", "Port to run the server on", "4321").option("-v, --verbose", "Enable verbose logging", false).option("--project-name <name>", "Name of the current project").option("--project-slug <slug>", "Slug of the current project").option("--no-seed", "Do not seed the database with demo data").option("--recreate-db", "Recreate the on-disk database on start", false).option("--memory", "Use in-memory database (no persistence)", false).option("--db-path <path>", "Custom path for the database file (relative to cwd or absolute)").option("--config-path <path>", "Path to playcademy.config.json (defaults to cwd)").option("--timeback-local", "Use local TimeBack instance").option("--timeback-oneroster-url <url>", "TimeBack OneRoster API URL").option("--timeback-caliper-url <url>", "TimeBack Caliper API URL").option("--timeback-course-id <id>", "TimeBack course ID for seeding").option("--timeback-student-id <id>", "TimeBack student ID for demo user").option("--timeback-role <role>", "TimeBack user role (student, parent, teacher, administrator)").option("--timeback-org-id <id>", "TimeBack organization ID").option("--timeback-org-name <name>", "TimeBack organization name").option("--timeback-org-type <type>", "TimeBack organization type (school, district, department)").option("-q, --quiet", "Quiet mode (suppress interactive messages)", false).action(async (options) => {
158596
+ program2.name("playcademy-sandbox").description("Local development server for Playcademy game development").version(version3).option("-p, --port <number>", "Port to run the server on", "4321").option("-v, --verbose", "Enable verbose logging", false).option("--project-name <name>", "Name of the current project").option("--project-slug <slug>", "Slug of the current project").option("--no-seed", "Do not seed the database with demo data").option("--recreate-db", "Recreate the on-disk database on start", false).option("--memory", "Use in-memory database (no persistence)", false).option("--db-path <path>", "Custom path for the database file (relative to cwd or absolute)").option("--config-path <path>", "Path to playcademy.config.json (defaults to cwd)").option("--timeback-local", "Use local TimeBack instance").option("--timeback-oneroster-url <url>", "TimeBack OneRoster API URL").option("--timeback-caliper-url <url>", "TimeBack Caliper API URL").option("--timeback-course-id <id>", "TimeBack course ID for seeding").option("--timeback-student-id <id>", "TimeBack student ID for demo user").option("--timeback-role <role>", "TimeBack user role (student, parent, teacher, administrator)").option("--timeback-org-id <id>", "TimeBack organization ID").option("--timeback-org-name <name>", "TimeBack organization name").option("--timeback-org-type <type>", "TimeBack organization type (school, district, department)").option("--timeback-excluded-courses <courses>", 'Comma-separated courses to exclude from enrollment (e.g. "FastMath:3,FastMath:4")').option("-q, --quiet", "Quiet mode (suppress interactive messages)", false).action(async (options) => {
158571
158597
  try {
158572
158598
  const startTime = Date.now();
158573
158599
  const port = parseInt(options.port);
@@ -158589,11 +158615,15 @@ program2.name("playcademy-sandbox").description("Local development server for Pl
158589
158615
  startedAt: Date.now(),
158590
158616
  projectRoot: process.cwd()
158591
158617
  });
158618
+ const totalCourses = project?.timebackCourses?.length ?? 0;
158619
+ const excludedCount = options.timebackExcludedCourses ? options.timebackExcludedCourses.split(",").filter(Boolean).length : 0;
158620
+ const enrolledCount = Math.max(0, totalCourses - excludedCount);
158592
158621
  printBanner({
158593
158622
  version: version3,
158594
158623
  port,
158595
158624
  startupTimeMs: Date.now() - startTime,
158596
- timebackCourseCount: project?.timebackCourses?.length,
158625
+ timebackCourseCount: totalCourses,
158626
+ timebackEnrolledCount: enrolledCount,
158597
158627
  quiet: options.quiet
158598
158628
  });
158599
158629
  const cleanup = () => {
package/dist/config.d.ts CHANGED
@@ -14,6 +14,13 @@ interface TimebackOrganizationInput {
14
14
  name?: string;
15
15
  type?: TimebackOrgType;
16
16
  }
17
+ /**
18
+ * Course enrollment overrides.
19
+ * - `'mock'` or omit: Use mock ID
20
+ * - Real string: Use that course ID
21
+ * - `null` or `false`: Exclude from enrollment
22
+ */
23
+ type CourseEnrollmentOverrides = Record<string, 'mock' | string | null | false>;
17
24
  /**
18
25
  * Timeback configuration input for sandbox.
19
26
  * All fields optional since they can be derived from defaults.
@@ -29,6 +36,7 @@ interface TimebackConfig {
29
36
  timebackId?: string;
30
37
  organization?: TimebackOrganizationInput;
31
38
  role?: TimebackUserRole;
39
+ courseOverrides?: CourseEnrollmentOverrides;
32
40
  }
33
41
  /**
34
42
  * Authentication configuration input for sandbox.
@@ -76,4 +84,4 @@ declare function getTimebackDisplayMode(): 'mock' | 'remote' | 'local' | null;
76
84
  declare const config: SandboxConfig;
77
85
 
78
86
  export { config, configureTimeback, getTimebackDisplayMode, hasTimebackCredentials, hasTimebackFullConfig, isTimebackEnabled, requireTimebackCredentials, setEmbeddedMode };
79
- export type { AuthConfig, SandboxConfig, TimebackConfig, TimebackMode };
87
+ export type { AuthConfig, CourseEnrollmentOverrides, SandboxConfig, TimebackConfig, TimebackMode };
package/dist/config.js CHANGED
@@ -127,6 +127,9 @@ function configureTimeback(options) {
127
127
  config.timeback.role = options.role;
128
128
  process.env.SANDBOX_TIMEBACK_ROLE = options.role;
129
129
  }
130
+ if (options.courseOverrides) {
131
+ config.timeback.courseOverrides = options.courseOverrides;
132
+ }
130
133
  }
131
134
  function getTimebackDisplayMode() {
132
135
  const { timebackId, mode } = config.timeback;
@@ -17,6 +17,7 @@ export declare function shouldMockTimeback(): boolean;
17
17
  export declare function getMockStudentProfile(): TimebackStudentProfile;
18
18
  /**
19
19
  * Generate mock enrollments from seeded game integrations.
20
+ * Respects courseOverrides from config - null/false excludes the course.
20
21
  */
21
22
  export declare function getMockEnrollments(db: DatabaseInstance): Promise<UserEnrollment[]>;
22
23
  /**
package/dist/server.d.ts CHANGED
@@ -15,6 +15,13 @@ interface TimebackOrganizationInput {
15
15
  name?: string;
16
16
  type?: TimebackOrgType;
17
17
  }
18
+ /**
19
+ * Course enrollment overrides.
20
+ * - `'mock'` or omit: Use mock ID
21
+ * - Real string: Use that course ID
22
+ * - `null` or `false`: Exclude from enrollment
23
+ */
24
+ type CourseEnrollmentOverrides = Record<string, 'mock' | string | null | false>;
18
25
  /**
19
26
  * Timeback configuration input for sandbox.
20
27
  * All fields optional since they can be derived from defaults.
@@ -30,6 +37,7 @@ interface TimebackConfig {
30
37
  timebackId?: string;
31
38
  organization?: TimebackOrganizationInput;
32
39
  role?: TimebackUserRole;
40
+ courseOverrides?: CourseEnrollmentOverrides;
33
41
  }
34
42
 
35
43
  /**
package/dist/server.js CHANGED
@@ -118699,6 +118699,9 @@ function configureTimeback(options) {
118699
118699
  config.timeback.role = options.role;
118700
118700
  process.env.SANDBOX_TIMEBACK_ROLE = options.role;
118701
118701
  }
118702
+ if (options.courseOverrides) {
118703
+ config.timeback.courseOverrides = options.courseOverrides;
118704
+ }
118702
118705
  }
118703
118706
  function getTimebackDisplayMode() {
118704
118707
  const { timebackId, mode } = config.timeback;
@@ -119568,7 +119571,7 @@ async function requirePortAvailable(port, timeoutMs = 100) {
119568
119571
  // package.json
119569
119572
  var package_default = {
119570
119573
  name: "@playcademy/sandbox",
119571
- version: "0.3.4",
119574
+ version: "0.3.6",
119572
119575
  description: "Local development server for Playcademy game development",
119573
119576
  type: "module",
119574
119577
  exports: {
@@ -150427,7 +150430,14 @@ function getMockStudentProfile() {
150427
150430
  }
150428
150431
  async function getMockEnrollments(db) {
150429
150432
  const allIntegrations = await db.query.gameTimebackIntegrations.findMany();
150430
- return allIntegrations.map((i4) => ({
150433
+ const overrides = config.timeback.courseOverrides;
150434
+ return allIntegrations.filter((i4) => {
150435
+ if (!overrides)
150436
+ return true;
150437
+ const key = `${i4.subject}:${i4.grade}`;
150438
+ const override = overrides[key];
150439
+ return override !== null && override !== false;
150440
+ }).map((i4) => ({
150431
150441
  gameId: i4.gameId,
150432
150442
  grade: i4.grade,
150433
150443
  subject: i4.subject,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/sandbox",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Local development server for Playcademy game development",
5
5
  "type": "module",
6
6
  "exports": {