@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 +11 -11
- package/dist/cli.js +41 -11
- package/dist/config.d.ts +9 -1
- package/dist/config.js +3 -0
- package/dist/mocks/timeback.d.ts +1 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +12 -2
- package/package.json +1 -1
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.
|
|
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
|
-
|
|
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:")}
|
|
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
|
-
|
|
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:
|
|
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;
|
package/dist/mocks/timeback.d.ts
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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,
|