@playcademy/vite-plugin 0.1.40 → 0.2.0
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 +76 -17
- package/dist/index.js +1395 -1006
- package/dist/lib/logging/adapter.d.ts +2 -2
- package/dist/lib/logging/index.d.ts +2 -2
- package/dist/lib/logging/utils.d.ts +11 -10
- package/dist/lib/sandbox/index.d.ts +1 -1
- package/dist/lib/sandbox/project-info.d.ts +1 -2
- package/dist/lib/sandbox/server.d.ts +3 -5
- package/dist/lib/sandbox/timeback.d.ts +31 -6
- package/dist/lib/sandbox/token.d.ts +25 -0
- package/dist/server/config-watcher.d.ts +15 -0
- package/dist/server/hotkeys/cycle-platform-role.d.ts +9 -0
- package/dist/server/middleware.d.ts +3 -4
- package/dist/server/recreate-sandbox.d.ts +21 -0
- package/dist/server/state.d.ts +10 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/internal.d.ts +59 -8
- package/dist/types/options.d.ts +61 -32
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -40990,105 +40990,6 @@ function closeBundleHook(context) {
|
|
|
40990
40990
|
// src/hooks/config.ts
|
|
40991
40991
|
import { DEFAULT_PORTS } from "playcademy/constants";
|
|
40992
40992
|
|
|
40993
|
-
// ../utils/src/port.ts
|
|
40994
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
40995
|
-
import { createServer } from "node:net";
|
|
40996
|
-
import { homedir } from "node:os";
|
|
40997
|
-
import { join } from "node:path";
|
|
40998
|
-
async function isPortAvailableOnHost(port, host) {
|
|
40999
|
-
return new Promise((resolve) => {
|
|
41000
|
-
const server = createServer();
|
|
41001
|
-
let resolved = false;
|
|
41002
|
-
const cleanup = (result) => {
|
|
41003
|
-
if (resolved)
|
|
41004
|
-
return;
|
|
41005
|
-
resolved = true;
|
|
41006
|
-
try {
|
|
41007
|
-
server.close();
|
|
41008
|
-
} catch {}
|
|
41009
|
-
resolve(result);
|
|
41010
|
-
};
|
|
41011
|
-
const timeout = setTimeout(() => cleanup(true), 100);
|
|
41012
|
-
server.once("error", (err2) => {
|
|
41013
|
-
clearTimeout(timeout);
|
|
41014
|
-
if (err2.code === "EAFNOSUPPORT" || err2.code === "EADDRNOTAVAIL") {
|
|
41015
|
-
cleanup(true);
|
|
41016
|
-
} else {
|
|
41017
|
-
cleanup(false);
|
|
41018
|
-
}
|
|
41019
|
-
});
|
|
41020
|
-
server.once("listening", () => {
|
|
41021
|
-
clearTimeout(timeout);
|
|
41022
|
-
cleanup(true);
|
|
41023
|
-
});
|
|
41024
|
-
server.listen(port, host).unref();
|
|
41025
|
-
});
|
|
41026
|
-
}
|
|
41027
|
-
async function findAvailablePort(startPort = 4321) {
|
|
41028
|
-
if (await isPortAvailableOnHost(startPort, "0.0.0.0")) {
|
|
41029
|
-
return startPort;
|
|
41030
|
-
} else {
|
|
41031
|
-
return findAvailablePort(startPort + 1);
|
|
41032
|
-
}
|
|
41033
|
-
}
|
|
41034
|
-
function getRegistryPath() {
|
|
41035
|
-
const home = homedir();
|
|
41036
|
-
const dir = join(home, ".playcademy");
|
|
41037
|
-
if (!existsSync(dir)) {
|
|
41038
|
-
mkdirSync(dir, { recursive: true });
|
|
41039
|
-
}
|
|
41040
|
-
return join(dir, ".proc");
|
|
41041
|
-
}
|
|
41042
|
-
function readRegistry() {
|
|
41043
|
-
const registryPath = getRegistryPath();
|
|
41044
|
-
if (!existsSync(registryPath)) {
|
|
41045
|
-
return {};
|
|
41046
|
-
}
|
|
41047
|
-
try {
|
|
41048
|
-
const content = readFileSync(registryPath, "utf-8");
|
|
41049
|
-
return JSON.parse(content);
|
|
41050
|
-
} catch {
|
|
41051
|
-
return {};
|
|
41052
|
-
}
|
|
41053
|
-
}
|
|
41054
|
-
function writeRegistry(registry) {
|
|
41055
|
-
const registryPath = getRegistryPath();
|
|
41056
|
-
writeFileSync(registryPath, JSON.stringify(registry, null, 2), "utf-8");
|
|
41057
|
-
}
|
|
41058
|
-
function getServerKey(type, port) {
|
|
41059
|
-
return `${type}-${port}`;
|
|
41060
|
-
}
|
|
41061
|
-
function writeServerInfo(type, info2) {
|
|
41062
|
-
const registry = readRegistry();
|
|
41063
|
-
const key = getServerKey(type, info2.port);
|
|
41064
|
-
registry[key] = info2;
|
|
41065
|
-
writeRegistry(registry);
|
|
41066
|
-
}
|
|
41067
|
-
function cleanupServerInfo(type, projectRoot, pid) {
|
|
41068
|
-
const registry = readRegistry();
|
|
41069
|
-
const keysToRemove = [];
|
|
41070
|
-
for (const [key, info2] of Object.entries(registry)) {
|
|
41071
|
-
if (key.startsWith(`${type}-`)) {
|
|
41072
|
-
let matches = true;
|
|
41073
|
-
if (projectRoot && info2.projectRoot !== projectRoot) {
|
|
41074
|
-
matches = false;
|
|
41075
|
-
}
|
|
41076
|
-
if (pid !== undefined && info2.pid !== pid) {
|
|
41077
|
-
matches = false;
|
|
41078
|
-
}
|
|
41079
|
-
if (matches) {
|
|
41080
|
-
keysToRemove.push(key);
|
|
41081
|
-
}
|
|
41082
|
-
}
|
|
41083
|
-
}
|
|
41084
|
-
for (const key of keysToRemove) {
|
|
41085
|
-
delete registry[key];
|
|
41086
|
-
}
|
|
41087
|
-
if (keysToRemove.length > 0) {
|
|
41088
|
-
writeRegistry(registry);
|
|
41089
|
-
}
|
|
41090
|
-
}
|
|
41091
|
-
|
|
41092
40993
|
// src/config/proxy.ts
|
|
41093
40994
|
function createProxyConfig(existingProxy, backendPort) {
|
|
41094
40995
|
if (existingProxy["/api"]) {
|
|
@@ -41122,7 +41023,8 @@ function createViteConfig(userConfig, backendPort) {
|
|
|
41122
41023
|
// src/hooks/config.ts
|
|
41123
41024
|
async function configHook(userConfig, context) {
|
|
41124
41025
|
process.noDeprecation = true;
|
|
41125
|
-
context.backendPort =
|
|
41026
|
+
context.backendPort = DEFAULT_PORTS.BACKEND;
|
|
41027
|
+
context.sandboxPort = DEFAULT_PORTS.SANDBOX;
|
|
41126
41028
|
return createViteConfig(userConfig, context.backendPort);
|
|
41127
41029
|
}
|
|
41128
41030
|
|
|
@@ -41141,8 +41043,12 @@ var serverState = {
|
|
|
41141
41043
|
backend: null,
|
|
41142
41044
|
viteServer: null,
|
|
41143
41045
|
currentMode: "platform",
|
|
41144
|
-
timebackRoleOverride: null
|
|
41046
|
+
timebackRoleOverride: null,
|
|
41047
|
+
platformRoleOverride: null
|
|
41145
41048
|
};
|
|
41049
|
+
function getSandboxRef() {
|
|
41050
|
+
return serverState.sandbox;
|
|
41051
|
+
}
|
|
41146
41052
|
function hasActiveServers() {
|
|
41147
41053
|
return !!(serverState.backend || serverState.sandbox);
|
|
41148
41054
|
}
|
|
@@ -41164,6 +41070,12 @@ function getTimebackRoleOverride() {
|
|
|
41164
41070
|
function setTimebackRoleOverride(role) {
|
|
41165
41071
|
serverState.timebackRoleOverride = role;
|
|
41166
41072
|
}
|
|
41073
|
+
function getPlatformRoleOverride() {
|
|
41074
|
+
return serverState.platformRoleOverride;
|
|
41075
|
+
}
|
|
41076
|
+
function setPlatformRoleOverride(role) {
|
|
41077
|
+
serverState.platformRoleOverride = role;
|
|
41078
|
+
}
|
|
41167
41079
|
|
|
41168
41080
|
// src/server/cleanup.ts
|
|
41169
41081
|
async function cleanupServers() {
|
|
@@ -41172,23 +41084,29 @@ async function cleanupServers() {
|
|
|
41172
41084
|
await serverState.backend.server.dispose();
|
|
41173
41085
|
serverState.backend.stopHotReload();
|
|
41174
41086
|
serverState.backend.cleanup();
|
|
41087
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
41175
41088
|
} catch {}
|
|
41176
41089
|
serverState.backend = null;
|
|
41177
41090
|
}
|
|
41178
41091
|
if (serverState.sandbox) {
|
|
41179
41092
|
try {
|
|
41180
|
-
serverState.sandbox.cleanup();
|
|
41093
|
+
await serverState.sandbox.cleanup();
|
|
41181
41094
|
} catch {}
|
|
41182
41095
|
serverState.sandbox = null;
|
|
41183
41096
|
}
|
|
41184
41097
|
}
|
|
41185
41098
|
|
|
41186
|
-
// src/server/
|
|
41187
|
-
|
|
41099
|
+
// src/server/config-watcher.ts
|
|
41100
|
+
import fs8 from "node:fs";
|
|
41101
|
+
import path6 from "node:path";
|
|
41102
|
+
import { CONFIG_FILE_NAMES } from "playcademy/constants";
|
|
41188
41103
|
|
|
41189
|
-
// src/
|
|
41190
|
-
var
|
|
41191
|
-
|
|
41104
|
+
// src/server/recreate-sandbox.ts
|
|
41105
|
+
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
41106
|
+
|
|
41107
|
+
// ../utils/src/vite-logger.ts
|
|
41108
|
+
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
41109
|
+
var { bold, cyan, dim } = import_picocolors2.default;
|
|
41192
41110
|
function formatTimestamp() {
|
|
41193
41111
|
const now = new Date;
|
|
41194
41112
|
const hours = now.getHours();
|
|
@@ -41196,32 +41114,19 @@ function formatTimestamp() {
|
|
|
41196
41114
|
const seconds = now.getSeconds().toString().padStart(2, "0");
|
|
41197
41115
|
const ampm = hours >= 12 ? "PM" : "AM";
|
|
41198
41116
|
const displayHours = hours % 12 || 12;
|
|
41199
|
-
return
|
|
41117
|
+
return dim(`${displayHours}:${minutes}:${seconds} ${ampm}`);
|
|
41200
41118
|
}
|
|
41201
|
-
function
|
|
41202
|
-
const
|
|
41203
|
-
const
|
|
41204
|
-
|
|
41205
|
-
|
|
41206
|
-
setTimebackRoleOverride(nextRole);
|
|
41207
|
-
logger.info(`${formatTimestamp()} ${import_picocolors2.default.cyan(import_picocolors2.default.bold("[playcademy]"))} ${import_picocolors2.default.dim("(timeback)")} ${import_picocolors2.default.red(currentRole)} → ${import_picocolors2.default.green(nextRole)}`);
|
|
41208
|
-
if (getViteServerRef()) {
|
|
41209
|
-
getViteServerRef()?.ws.send({ type: "full-reload", path: "*" });
|
|
41210
|
-
} else {
|
|
41211
|
-
logger.warn(`${formatTimestamp()} ${import_picocolors2.default.red(import_picocolors2.bold("[playcademy]"))} ${import_picocolors2.dim("(timeback)")} ${import_picocolors2.yellow("Cannot cycle TimeBack role: no Vite server reference")}`);
|
|
41119
|
+
function createLogPrefix(entity, domain) {
|
|
41120
|
+
const timestamp = formatTimestamp();
|
|
41121
|
+
const label = bold(cyan(`[${entity}]`));
|
|
41122
|
+
if (domain) {
|
|
41123
|
+
return `${timestamp} ${label} ${dim(`(${domain})`)}`;
|
|
41212
41124
|
}
|
|
41125
|
+
return `${timestamp} ${label}`;
|
|
41213
41126
|
}
|
|
41214
|
-
var cycleTimebackRoleHotkey = (options) => ({
|
|
41215
|
-
key: "t",
|
|
41216
|
-
description: "cycle TimeBack role",
|
|
41217
|
-
action: () => cycleTimebackRole(options.viteConfig.logger)
|
|
41218
|
-
});
|
|
41219
|
-
|
|
41220
|
-
// src/server/hotkeys/recreate-database.ts
|
|
41221
|
-
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
41222
41127
|
|
|
41223
41128
|
// src/lib/sandbox/server.ts
|
|
41224
|
-
var
|
|
41129
|
+
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
41225
41130
|
import { DEFAULT_PORTS as DEFAULT_PORTS2 } from "playcademy/constants";
|
|
41226
41131
|
|
|
41227
41132
|
// ../sandbox/dist/server.js
|
|
@@ -41258,20 +41163,24 @@ import { Http2ServerRequest as Http2ServerRequest2 } from "http2";
|
|
|
41258
41163
|
import { Http2ServerRequest } from "http2";
|
|
41259
41164
|
import { Readable } from "stream";
|
|
41260
41165
|
import crypto2 from "crypto";
|
|
41166
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "node:fs";
|
|
41167
|
+
import { createServer } from "node:net";
|
|
41168
|
+
import { homedir } from "node:os";
|
|
41169
|
+
import { join as join2 } from "node:path";
|
|
41261
41170
|
import fs5 from "node:fs";
|
|
41262
41171
|
import fs3 from "node:fs";
|
|
41263
41172
|
import fs22 from "node:fs";
|
|
41264
|
-
import { dirname, isAbsolute, join as
|
|
41173
|
+
import { dirname, isAbsolute, join as join3 } from "node:path";
|
|
41265
41174
|
import path2 from "path";
|
|
41266
41175
|
import { stdout } from "process";
|
|
41267
41176
|
import { createPublicKey as createPublicKey2, createVerify, verify as verify3 } from "crypto";
|
|
41268
41177
|
import { request as request2 } from "https";
|
|
41269
41178
|
import { pipeline } from "stream";
|
|
41270
41179
|
import { readdir as readdir2, readFile as readFile2, stat } from "node:fs/promises";
|
|
41271
|
-
import { join as
|
|
41180
|
+
import { join as join5, relative } from "node:path";
|
|
41272
41181
|
import { createHash } from "node:crypto";
|
|
41273
41182
|
import { readdir, readFile } from "node:fs/promises";
|
|
41274
|
-
import { join as
|
|
41183
|
+
import { join as join4 } from "node:path";
|
|
41275
41184
|
import crypto6 from "node:crypto";
|
|
41276
41185
|
import * as crypto7 from "node:crypto";
|
|
41277
41186
|
var __create2 = Object.create;
|
|
@@ -45601,7 +45510,7 @@ var require_node22 = __commonJS2((exports) => {
|
|
|
45601
45510
|
return path3;
|
|
45602
45511
|
}
|
|
45603
45512
|
exports2.normalize = normalize;
|
|
45604
|
-
function
|
|
45513
|
+
function join22(aRoot, aPath) {
|
|
45605
45514
|
if (aRoot === "") {
|
|
45606
45515
|
aRoot = ".";
|
|
45607
45516
|
}
|
|
@@ -45633,7 +45542,7 @@ var require_node22 = __commonJS2((exports) => {
|
|
|
45633
45542
|
}
|
|
45634
45543
|
return joined;
|
|
45635
45544
|
}
|
|
45636
|
-
exports2.join =
|
|
45545
|
+
exports2.join = join22;
|
|
45637
45546
|
exports2.isAbsolute = function(aPath) {
|
|
45638
45547
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
45639
45548
|
};
|
|
@@ -45806,7 +45715,7 @@ var require_node22 = __commonJS2((exports) => {
|
|
|
45806
45715
|
parsed.path = parsed.path.substring(0, index2 + 1);
|
|
45807
45716
|
}
|
|
45808
45717
|
}
|
|
45809
|
-
sourceURL =
|
|
45718
|
+
sourceURL = join22(urlGenerate(parsed), sourceURL);
|
|
45810
45719
|
}
|
|
45811
45720
|
return normalize(sourceURL);
|
|
45812
45721
|
}
|
|
@@ -49532,16 +49441,16 @@ If you have no idea what this means or what Pirates is, let me explain: Pirates
|
|
|
49532
49441
|
return walkForTsConfig(parentDirectory, readdirSync);
|
|
49533
49442
|
}
|
|
49534
49443
|
exports2.walkForTsConfig = walkForTsConfig;
|
|
49535
|
-
function loadTsconfig(configFilePath,
|
|
49536
|
-
if (
|
|
49537
|
-
|
|
49444
|
+
function loadTsconfig(configFilePath, existsSync3, readFileSync2) {
|
|
49445
|
+
if (existsSync3 === undefined) {
|
|
49446
|
+
existsSync3 = fs32.existsSync;
|
|
49538
49447
|
}
|
|
49539
49448
|
if (readFileSync2 === undefined) {
|
|
49540
49449
|
readFileSync2 = function(filename) {
|
|
49541
49450
|
return fs32.readFileSync(filename, "utf8");
|
|
49542
49451
|
};
|
|
49543
49452
|
}
|
|
49544
|
-
if (!
|
|
49453
|
+
if (!existsSync3(configFilePath)) {
|
|
49545
49454
|
return;
|
|
49546
49455
|
}
|
|
49547
49456
|
var configString = readFileSync2(configFilePath);
|
|
@@ -49557,27 +49466,27 @@ If you have no idea what this means or what Pirates is, let me explain: Pirates
|
|
|
49557
49466
|
var base = undefined;
|
|
49558
49467
|
if (Array.isArray(extendedConfig)) {
|
|
49559
49468
|
base = extendedConfig.reduce(function(currBase, extendedConfigElement) {
|
|
49560
|
-
return mergeTsconfigs(currBase, loadTsconfigFromExtends(configFilePath, extendedConfigElement,
|
|
49469
|
+
return mergeTsconfigs(currBase, loadTsconfigFromExtends(configFilePath, extendedConfigElement, existsSync3, readFileSync2));
|
|
49561
49470
|
}, {});
|
|
49562
49471
|
} else {
|
|
49563
|
-
base = loadTsconfigFromExtends(configFilePath, extendedConfig,
|
|
49472
|
+
base = loadTsconfigFromExtends(configFilePath, extendedConfig, existsSync3, readFileSync2);
|
|
49564
49473
|
}
|
|
49565
49474
|
return mergeTsconfigs(base, config2);
|
|
49566
49475
|
}
|
|
49567
49476
|
return config2;
|
|
49568
49477
|
}
|
|
49569
49478
|
exports2.loadTsconfig = loadTsconfig;
|
|
49570
|
-
function loadTsconfigFromExtends(configFilePath, extendedConfigValue,
|
|
49479
|
+
function loadTsconfigFromExtends(configFilePath, extendedConfigValue, existsSync3, readFileSync2) {
|
|
49571
49480
|
var _a;
|
|
49572
49481
|
if (typeof extendedConfigValue === "string" && extendedConfigValue.indexOf(".json") === -1) {
|
|
49573
49482
|
extendedConfigValue += ".json";
|
|
49574
49483
|
}
|
|
49575
49484
|
var currentDir = path3.dirname(configFilePath);
|
|
49576
49485
|
var extendedConfigPath = path3.join(currentDir, extendedConfigValue);
|
|
49577
|
-
if (extendedConfigValue.indexOf("/") !== -1 && extendedConfigValue.indexOf(".") !== -1 && !
|
|
49486
|
+
if (extendedConfigValue.indexOf("/") !== -1 && extendedConfigValue.indexOf(".") !== -1 && !existsSync3(extendedConfigPath)) {
|
|
49578
49487
|
extendedConfigPath = path3.join(currentDir, "node_modules", extendedConfigValue);
|
|
49579
49488
|
}
|
|
49580
|
-
var config2 = loadTsconfig(extendedConfigPath,
|
|
49489
|
+
var config2 = loadTsconfig(extendedConfigPath, existsSync3, readFileSync2) || {};
|
|
49581
49490
|
if ((_a = config2.compilerOptions) === null || _a === undefined ? undefined : _a.baseUrl) {
|
|
49582
49491
|
var extendsDir = path3.dirname(extendedConfigValue);
|
|
49583
49492
|
config2.compilerOptions.baseUrl = path3.join(extendsDir, config2.compilerOptions.baseUrl);
|
|
@@ -76048,7 +75957,7 @@ globstar while`, file, fr, pattern, pr2, swallowee);
|
|
|
76048
75957
|
return new SQL2([new StringChunk2(str)]);
|
|
76049
75958
|
}
|
|
76050
75959
|
sql22.raw = raw2;
|
|
76051
|
-
function
|
|
75960
|
+
function join42(chunks, separator) {
|
|
76052
75961
|
const result = [];
|
|
76053
75962
|
for (const [i3, chunk] of chunks.entries()) {
|
|
76054
75963
|
if (i3 > 0 && separator !== undefined) {
|
|
@@ -76058,7 +75967,7 @@ globstar while`, file, fr, pattern, pr2, swallowee);
|
|
|
76058
75967
|
}
|
|
76059
75968
|
return new SQL2(result);
|
|
76060
75969
|
}
|
|
76061
|
-
sql22.join =
|
|
75970
|
+
sql22.join = join42;
|
|
76062
75971
|
function identifier(value) {
|
|
76063
75972
|
return new Name2(value);
|
|
76064
75973
|
}
|
|
@@ -78888,7 +78797,7 @@ params: ${params}`);
|
|
|
78888
78797
|
const tableName = getTableLikeName2(table62);
|
|
78889
78798
|
for (const item of extractUsedTable(table62))
|
|
78890
78799
|
this.usedTables.add(item);
|
|
78891
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
78800
|
+
if (typeof tableName === "string" && this.config.joins?.some((join42) => join42.alias === tableName)) {
|
|
78892
78801
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
78893
78802
|
}
|
|
78894
78803
|
if (!this.isPartialSelect) {
|
|
@@ -79746,7 +79655,7 @@ params: ${params}`);
|
|
|
79746
79655
|
createJoin(joinType) {
|
|
79747
79656
|
return (table62, on2) => {
|
|
79748
79657
|
const tableName = getTableLikeName2(table62);
|
|
79749
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
79658
|
+
if (typeof tableName === "string" && this.config.joins.some((join42) => join42.alias === tableName)) {
|
|
79750
79659
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
79751
79660
|
}
|
|
79752
79661
|
if (typeof on2 === "function") {
|
|
@@ -79792,10 +79701,10 @@ params: ${params}`);
|
|
|
79792
79701
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
79793
79702
|
fields[tableName] = fromFields;
|
|
79794
79703
|
}
|
|
79795
|
-
for (const
|
|
79796
|
-
const tableName2 = getTableLikeName2(
|
|
79797
|
-
if (typeof tableName2 === "string" && !is2(
|
|
79798
|
-
const fromFields = this.getTableLikeFields(
|
|
79704
|
+
for (const join42 of this.config.joins) {
|
|
79705
|
+
const tableName2 = getTableLikeName2(join42.table);
|
|
79706
|
+
if (typeof tableName2 === "string" && !is2(join42.table, SQL2)) {
|
|
79707
|
+
const fromFields = this.getTableLikeFields(join42.table);
|
|
79799
79708
|
fields[tableName2] = fromFields;
|
|
79800
79709
|
}
|
|
79801
79710
|
}
|
|
@@ -83370,7 +83279,7 @@ ORDER BY
|
|
|
83370
83279
|
const tableName = getTableLikeName2(table62);
|
|
83371
83280
|
for (const item of extractUsedTable2(table62))
|
|
83372
83281
|
this.usedTables.add(item);
|
|
83373
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
83282
|
+
if (typeof tableName === "string" && this.config.joins?.some((join42) => join42.alias === tableName)) {
|
|
83374
83283
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
83375
83284
|
}
|
|
83376
83285
|
if (!this.isPartialSelect) {
|
|
@@ -83811,7 +83720,7 @@ ORDER BY
|
|
|
83811
83720
|
createJoin(joinType) {
|
|
83812
83721
|
return (table62, on2) => {
|
|
83813
83722
|
const tableName = getTableLikeName2(table62);
|
|
83814
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
83723
|
+
if (typeof tableName === "string" && this.config.joins.some((join42) => join42.alias === tableName)) {
|
|
83815
83724
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
83816
83725
|
}
|
|
83817
83726
|
if (typeof on2 === "function") {
|
|
@@ -87418,7 +87327,7 @@ ${withStyle.errorWarning(`We've found duplicated view name across ${source_defau
|
|
|
87418
87327
|
const tableName = getTableLikeName2(table62);
|
|
87419
87328
|
for (const item of extractUsedTable3(table62))
|
|
87420
87329
|
this.usedTables.add(item);
|
|
87421
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
87330
|
+
if (typeof tableName === "string" && this.config.joins?.some((join42) => join42.alias === tableName)) {
|
|
87422
87331
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
87423
87332
|
}
|
|
87424
87333
|
if (!this.isPartialSelect) {
|
|
@@ -91460,7 +91369,7 @@ AND
|
|
|
91460
91369
|
const tableName = getTableLikeName2(table62);
|
|
91461
91370
|
for (const item of extractUsedTable4(table62))
|
|
91462
91371
|
this.usedTables.add(item);
|
|
91463
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
91372
|
+
if (typeof tableName === "string" && this.config.joins?.some((join42) => join42.alias === tableName)) {
|
|
91464
91373
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
91465
91374
|
}
|
|
91466
91375
|
if (!this.isPartialSelect) {
|
|
@@ -162051,10 +161960,10 @@ var require_colorette = __commonJS2((exports) => {
|
|
|
162051
161960
|
black,
|
|
162052
161961
|
red,
|
|
162053
161962
|
green,
|
|
162054
|
-
yellow
|
|
161963
|
+
yellow,
|
|
162055
161964
|
blue,
|
|
162056
161965
|
magenta,
|
|
162057
|
-
cyan,
|
|
161966
|
+
cyan: cyan2,
|
|
162058
161967
|
white,
|
|
162059
161968
|
gray,
|
|
162060
161969
|
bgBlack,
|
|
@@ -162104,7 +162013,7 @@ var require_colorette = __commonJS2((exports) => {
|
|
|
162104
162013
|
exports.blueBright = blueBright;
|
|
162105
162014
|
exports.bold = bold2;
|
|
162106
162015
|
exports.createColors = createColors;
|
|
162107
|
-
exports.cyan =
|
|
162016
|
+
exports.cyan = cyan2;
|
|
162108
162017
|
exports.cyanBright = cyanBright;
|
|
162109
162018
|
exports.dim = dim2;
|
|
162110
162019
|
exports.gray = gray;
|
|
@@ -162123,7 +162032,7 @@ var require_colorette = __commonJS2((exports) => {
|
|
|
162123
162032
|
exports.underline = underline;
|
|
162124
162033
|
exports.white = white;
|
|
162125
162034
|
exports.whiteBright = whiteBright;
|
|
162126
|
-
exports.yellow =
|
|
162035
|
+
exports.yellow = yellow;
|
|
162127
162036
|
exports.yellowBright = yellowBright;
|
|
162128
162037
|
});
|
|
162129
162038
|
var require_dist22 = __commonJS2((exports) => {
|
|
@@ -175066,7 +174975,7 @@ function hasTimebackCredentials() {
|
|
|
175066
174975
|
return false;
|
|
175067
174976
|
}
|
|
175068
174977
|
function hasTimebackFullConfig() {
|
|
175069
|
-
return hasTimebackCredentials() && !!(config.timeback.courseId && config.timeback.
|
|
174978
|
+
return hasTimebackCredentials() && !!(config.timeback.courseId && config.timeback.timebackId);
|
|
175070
174979
|
}
|
|
175071
174980
|
function requireTimebackCredentials() {
|
|
175072
174981
|
if (hasTimebackCredentials())
|
|
@@ -175120,11 +175029,36 @@ function configureTimeback(options) {
|
|
|
175120
175029
|
config.timeback.courseId = options.courseId;
|
|
175121
175030
|
process.env.SANDBOX_TIMEBACK_COURSE_ID = options.courseId;
|
|
175122
175031
|
}
|
|
175123
|
-
if (options.
|
|
175124
|
-
config.timeback.
|
|
175125
|
-
process.env.SANDBOX_TIMEBACK_STUDENT_ID = options.
|
|
175032
|
+
if (options.timebackId) {
|
|
175033
|
+
config.timeback.timebackId = options.timebackId;
|
|
175034
|
+
process.env.SANDBOX_TIMEBACK_STUDENT_ID = options.timebackId;
|
|
175035
|
+
const isMockMode = options.timebackId === "mock";
|
|
175036
|
+
process.env.SANDBOX_TIMEBACK_MOCK_MODE = isMockMode ? "true" : "false";
|
|
175037
|
+
}
|
|
175038
|
+
if (options.organization) {
|
|
175039
|
+
config.timeback.organization = options.organization;
|
|
175040
|
+
process.env.SANDBOX_TIMEBACK_ORG_ID = options.organization.id;
|
|
175041
|
+
if (options.organization.name) {
|
|
175042
|
+
process.env.SANDBOX_TIMEBACK_ORG_NAME = options.organization.name;
|
|
175043
|
+
}
|
|
175044
|
+
if (options.organization.type) {
|
|
175045
|
+
process.env.SANDBOX_TIMEBACK_ORG_TYPE = options.organization.type;
|
|
175046
|
+
}
|
|
175047
|
+
}
|
|
175048
|
+
if (options.role) {
|
|
175049
|
+
config.timeback.role = options.role;
|
|
175050
|
+
process.env.SANDBOX_TIMEBACK_ROLE = options.role;
|
|
175126
175051
|
}
|
|
175127
175052
|
}
|
|
175053
|
+
function getTimebackDisplayMode() {
|
|
175054
|
+
const { timebackId, mode } = config.timeback;
|
|
175055
|
+
if (!timebackId)
|
|
175056
|
+
return null;
|
|
175057
|
+
if (timebackId === "mock" || !hasTimebackCredentials()) {
|
|
175058
|
+
return "mock";
|
|
175059
|
+
}
|
|
175060
|
+
return mode;
|
|
175061
|
+
}
|
|
175128
175062
|
function setEmbeddedMode(embedded) {
|
|
175129
175063
|
config.embedded = embedded;
|
|
175130
175064
|
process.env.PLAYCADEMY_EMBEDDED = embedded ? "1" : undefined;
|
|
@@ -175143,12 +175077,199 @@ var config = {
|
|
|
175143
175077
|
clientSecret: process.env.TIMEBACK_API_CLIENT_SECRET,
|
|
175144
175078
|
authUrl: process.env.TIMEBACK_API_AUTH_URL,
|
|
175145
175079
|
courseId: process.env.SANDBOX_TIMEBACK_COURSE_ID,
|
|
175146
|
-
|
|
175080
|
+
timebackId: process.env.SANDBOX_TIMEBACK_STUDENT_ID
|
|
175147
175081
|
}
|
|
175148
175082
|
};
|
|
175149
175083
|
process.env.BETTER_AUTH_SECRET = config.auth.betterAuthSecret;
|
|
175150
175084
|
process.env.GAME_JWT_SECRET = config.auth.gameJwtSecret;
|
|
175151
175085
|
process.env.PUBLIC_IS_LOCAL = "true";
|
|
175086
|
+
var now = new Date;
|
|
175087
|
+
var DEMO_USER_IDS = {
|
|
175088
|
+
player: "00000000-0000-0000-0000-000000000001",
|
|
175089
|
+
developer: "00000000-0000-0000-0000-000000000002",
|
|
175090
|
+
admin: "00000000-0000-0000-0000-000000000003",
|
|
175091
|
+
pendingDeveloper: "00000000-0000-0000-0000-000000000004",
|
|
175092
|
+
unverifiedPlayer: "00000000-0000-0000-0000-000000000005"
|
|
175093
|
+
};
|
|
175094
|
+
var DEMO_USERS = {
|
|
175095
|
+
admin: {
|
|
175096
|
+
id: DEMO_USER_IDS.admin,
|
|
175097
|
+
name: "Admin User",
|
|
175098
|
+
username: "admin_user",
|
|
175099
|
+
email: "admin@playcademy.com",
|
|
175100
|
+
emailVerified: true,
|
|
175101
|
+
image: null,
|
|
175102
|
+
role: "admin",
|
|
175103
|
+
developerStatus: "approved",
|
|
175104
|
+
createdAt: now,
|
|
175105
|
+
updatedAt: now
|
|
175106
|
+
},
|
|
175107
|
+
player: {
|
|
175108
|
+
id: DEMO_USER_IDS.player,
|
|
175109
|
+
name: "Player User",
|
|
175110
|
+
username: "player_user",
|
|
175111
|
+
email: "player@playcademy.com",
|
|
175112
|
+
emailVerified: true,
|
|
175113
|
+
image: null,
|
|
175114
|
+
role: "player",
|
|
175115
|
+
developerStatus: "none",
|
|
175116
|
+
createdAt: now,
|
|
175117
|
+
updatedAt: now
|
|
175118
|
+
},
|
|
175119
|
+
developer: {
|
|
175120
|
+
id: DEMO_USER_IDS.developer,
|
|
175121
|
+
name: "Developer User",
|
|
175122
|
+
username: "developer_user",
|
|
175123
|
+
email: "developer@playcademy.com",
|
|
175124
|
+
emailVerified: true,
|
|
175125
|
+
image: null,
|
|
175126
|
+
role: "developer",
|
|
175127
|
+
developerStatus: "approved",
|
|
175128
|
+
createdAt: now,
|
|
175129
|
+
updatedAt: now
|
|
175130
|
+
},
|
|
175131
|
+
pendingDeveloper: {
|
|
175132
|
+
id: DEMO_USER_IDS.pendingDeveloper,
|
|
175133
|
+
name: "Pending Developer",
|
|
175134
|
+
username: "pending_dev",
|
|
175135
|
+
email: "pending@playcademy.com",
|
|
175136
|
+
emailVerified: true,
|
|
175137
|
+
image: null,
|
|
175138
|
+
role: "developer",
|
|
175139
|
+
developerStatus: "pending",
|
|
175140
|
+
createdAt: now,
|
|
175141
|
+
updatedAt: now
|
|
175142
|
+
},
|
|
175143
|
+
unverifiedPlayer: {
|
|
175144
|
+
id: DEMO_USER_IDS.unverifiedPlayer,
|
|
175145
|
+
name: "Unverified Player",
|
|
175146
|
+
username: "unverified_player",
|
|
175147
|
+
email: "unverified@playcademy.com",
|
|
175148
|
+
emailVerified: false,
|
|
175149
|
+
image: null,
|
|
175150
|
+
role: "player",
|
|
175151
|
+
developerStatus: "none",
|
|
175152
|
+
createdAt: now,
|
|
175153
|
+
updatedAt: now
|
|
175154
|
+
}
|
|
175155
|
+
};
|
|
175156
|
+
var DEMO_USER = DEMO_USERS.player;
|
|
175157
|
+
var DEMO_TOKENS = {
|
|
175158
|
+
"sandbox-demo-token": DEMO_USERS.player,
|
|
175159
|
+
"sandbox-admin-token": DEMO_USERS.admin,
|
|
175160
|
+
"sandbox-player-token": DEMO_USERS.player,
|
|
175161
|
+
"sandbox-developer-token": DEMO_USERS.developer,
|
|
175162
|
+
"sandbox-pending-dev-token": DEMO_USERS.pendingDeveloper,
|
|
175163
|
+
"sandbox-unverified-token": DEMO_USERS.unverifiedPlayer,
|
|
175164
|
+
"mock-game-token-for-local-dev": DEMO_USERS.player
|
|
175165
|
+
};
|
|
175166
|
+
var DEMO_TOKEN = "sandbox-demo-token";
|
|
175167
|
+
var MOCK_GAME_ID = "mock-game-id-from-template";
|
|
175168
|
+
var DEMO_ITEM_IDS = {
|
|
175169
|
+
playcademyCredits: "10000000-0000-0000-0000-000000000001",
|
|
175170
|
+
foundingMemberBadge: "10000000-0000-0000-0000-000000000002",
|
|
175171
|
+
earlyAdopterBadge: "10000000-0000-0000-0000-000000000003",
|
|
175172
|
+
firstGameBadge: "10000000-0000-0000-0000-000000000004",
|
|
175173
|
+
commonSword: "10000000-0000-0000-0000-000000000005",
|
|
175174
|
+
smallHealthPotion: "10000000-0000-0000-0000-000000000006",
|
|
175175
|
+
smallBackpack: "10000000-0000-0000-0000-000000000007"
|
|
175176
|
+
};
|
|
175177
|
+
var PLAYCADEMY_CREDITS_ID = DEMO_ITEM_IDS.playcademyCredits;
|
|
175178
|
+
var SAMPLE_ITEMS = [
|
|
175179
|
+
{
|
|
175180
|
+
id: PLAYCADEMY_CREDITS_ID,
|
|
175181
|
+
slug: "PLAYCADEMY_CREDITS",
|
|
175182
|
+
gameId: null,
|
|
175183
|
+
displayName: "PLAYCADEMY credits",
|
|
175184
|
+
description: "The main currency used across PLAYCADEMY.",
|
|
175185
|
+
type: "currency",
|
|
175186
|
+
isPlaceable: false,
|
|
175187
|
+
imageUrl: "http://playcademy-sandbox.local/playcademy-credit.png",
|
|
175188
|
+
metadata: {
|
|
175189
|
+
rarity: "common"
|
|
175190
|
+
}
|
|
175191
|
+
},
|
|
175192
|
+
{
|
|
175193
|
+
id: DEMO_ITEM_IDS.foundingMemberBadge,
|
|
175194
|
+
slug: "FOUNDING_MEMBER_BADGE",
|
|
175195
|
+
gameId: null,
|
|
175196
|
+
displayName: "Founding Member Badge",
|
|
175197
|
+
description: "Reserved for founding core team of the PLAYCADEMY platform.",
|
|
175198
|
+
type: "badge",
|
|
175199
|
+
isPlaceable: false,
|
|
175200
|
+
imageUrl: null,
|
|
175201
|
+
metadata: {
|
|
175202
|
+
rarity: "legendary"
|
|
175203
|
+
}
|
|
175204
|
+
},
|
|
175205
|
+
{
|
|
175206
|
+
id: DEMO_ITEM_IDS.earlyAdopterBadge,
|
|
175207
|
+
slug: "EARLY_ADOPTER_BADGE",
|
|
175208
|
+
gameId: null,
|
|
175209
|
+
displayName: "Early Adopter Badge",
|
|
175210
|
+
description: "Awarded to users who joined during the beta phase.",
|
|
175211
|
+
type: "badge",
|
|
175212
|
+
isPlaceable: false,
|
|
175213
|
+
imageUrl: null,
|
|
175214
|
+
metadata: {
|
|
175215
|
+
rarity: "epic"
|
|
175216
|
+
}
|
|
175217
|
+
},
|
|
175218
|
+
{
|
|
175219
|
+
id: DEMO_ITEM_IDS.firstGameBadge,
|
|
175220
|
+
slug: "FIRST_GAME_BADGE",
|
|
175221
|
+
gameId: null,
|
|
175222
|
+
displayName: "First Game Played",
|
|
175223
|
+
description: "Awarded for playing your first game in the Playcademy platform.",
|
|
175224
|
+
type: "badge",
|
|
175225
|
+
isPlaceable: false,
|
|
175226
|
+
imageUrl: "http://playcademy-sandbox.local/first-game-badge.png",
|
|
175227
|
+
metadata: {
|
|
175228
|
+
rarity: "uncommon"
|
|
175229
|
+
}
|
|
175230
|
+
},
|
|
175231
|
+
{
|
|
175232
|
+
id: DEMO_ITEM_IDS.commonSword,
|
|
175233
|
+
slug: "COMMON_SWORD",
|
|
175234
|
+
gameId: null,
|
|
175235
|
+
displayName: "Common Sword",
|
|
175236
|
+
description: "A basic sword, good for beginners.",
|
|
175237
|
+
type: "unlock",
|
|
175238
|
+
isPlaceable: false,
|
|
175239
|
+
imageUrl: "http://playcademy-sandbox.local/common-sword.png",
|
|
175240
|
+
metadata: undefined
|
|
175241
|
+
},
|
|
175242
|
+
{
|
|
175243
|
+
id: DEMO_ITEM_IDS.smallHealthPotion,
|
|
175244
|
+
slug: "SMALL_HEALTH_POTION",
|
|
175245
|
+
gameId: null,
|
|
175246
|
+
displayName: "Small Health Potion",
|
|
175247
|
+
description: "Restores a small amount of health.",
|
|
175248
|
+
type: "other",
|
|
175249
|
+
isPlaceable: false,
|
|
175250
|
+
imageUrl: "http://playcademy-sandbox.local/small-health-potion.png",
|
|
175251
|
+
metadata: undefined
|
|
175252
|
+
},
|
|
175253
|
+
{
|
|
175254
|
+
id: DEMO_ITEM_IDS.smallBackpack,
|
|
175255
|
+
slug: "SMALL_BACKPACK",
|
|
175256
|
+
gameId: null,
|
|
175257
|
+
displayName: "Small Backpack",
|
|
175258
|
+
description: "Increases your inventory capacity by 5 slots.",
|
|
175259
|
+
type: "upgrade",
|
|
175260
|
+
isPlaceable: false,
|
|
175261
|
+
imageUrl: "http://playcademy-sandbox.local/small-backpack.png",
|
|
175262
|
+
metadata: undefined
|
|
175263
|
+
}
|
|
175264
|
+
];
|
|
175265
|
+
var SAMPLE_INVENTORY = [
|
|
175266
|
+
{
|
|
175267
|
+
id: "20000000-0000-0000-0000-000000000001",
|
|
175268
|
+
userId: DEMO_USER.id,
|
|
175269
|
+
itemId: PLAYCADEMY_CREDITS_ID,
|
|
175270
|
+
quantity: 1000
|
|
175271
|
+
}
|
|
175272
|
+
];
|
|
175152
175273
|
var RequestError = class extends Error {
|
|
175153
175274
|
constructor(message3, options) {
|
|
175154
175275
|
super(message3, options);
|
|
@@ -175684,9 +175805,99 @@ var serve = (options, listeningListener) => {
|
|
|
175684
175805
|
});
|
|
175685
175806
|
return server;
|
|
175686
175807
|
};
|
|
175808
|
+
function getRegistryPath() {
|
|
175809
|
+
const home = homedir();
|
|
175810
|
+
const dir = join2(home, ".playcademy");
|
|
175811
|
+
if (!existsSync2(dir)) {
|
|
175812
|
+
mkdirSync2(dir, { recursive: true });
|
|
175813
|
+
}
|
|
175814
|
+
return join2(dir, ".proc");
|
|
175815
|
+
}
|
|
175816
|
+
function readRegistry() {
|
|
175817
|
+
const registryPath = getRegistryPath();
|
|
175818
|
+
if (!existsSync2(registryPath)) {
|
|
175819
|
+
return {};
|
|
175820
|
+
}
|
|
175821
|
+
try {
|
|
175822
|
+
const content = readFileSync(registryPath, "utf-8");
|
|
175823
|
+
return JSON.parse(content);
|
|
175824
|
+
} catch {
|
|
175825
|
+
return {};
|
|
175826
|
+
}
|
|
175827
|
+
}
|
|
175828
|
+
function writeRegistry(registry) {
|
|
175829
|
+
const registryPath = getRegistryPath();
|
|
175830
|
+
writeFileSync(registryPath, JSON.stringify(registry, null, 2), "utf-8");
|
|
175831
|
+
}
|
|
175832
|
+
function getServerKey(type, port) {
|
|
175833
|
+
return `${type}-${port}`;
|
|
175834
|
+
}
|
|
175835
|
+
function writeServerInfo(type, info2) {
|
|
175836
|
+
const registry = readRegistry();
|
|
175837
|
+
const key = getServerKey(type, info2.port);
|
|
175838
|
+
registry[key] = info2;
|
|
175839
|
+
writeRegistry(registry);
|
|
175840
|
+
}
|
|
175841
|
+
function cleanupServerInfo(type, projectRoot, pid) {
|
|
175842
|
+
const registry = readRegistry();
|
|
175843
|
+
const keysToRemove = [];
|
|
175844
|
+
for (const [key, info2] of Object.entries(registry)) {
|
|
175845
|
+
if (key.startsWith(`${type}-`)) {
|
|
175846
|
+
let matches = true;
|
|
175847
|
+
if (projectRoot && info2.projectRoot !== projectRoot) {
|
|
175848
|
+
matches = false;
|
|
175849
|
+
}
|
|
175850
|
+
if (pid !== undefined && info2.pid !== pid) {
|
|
175851
|
+
matches = false;
|
|
175852
|
+
}
|
|
175853
|
+
if (matches) {
|
|
175854
|
+
keysToRemove.push(key);
|
|
175855
|
+
}
|
|
175856
|
+
}
|
|
175857
|
+
}
|
|
175858
|
+
for (const key of keysToRemove) {
|
|
175859
|
+
delete registry[key];
|
|
175860
|
+
}
|
|
175861
|
+
if (keysToRemove.length > 0) {
|
|
175862
|
+
writeRegistry(registry);
|
|
175863
|
+
}
|
|
175864
|
+
}
|
|
175865
|
+
async function isPortInUse(port) {
|
|
175866
|
+
return new Promise((resolve2) => {
|
|
175867
|
+
const server = createServer();
|
|
175868
|
+
server.once("error", () => {
|
|
175869
|
+
resolve2(true);
|
|
175870
|
+
});
|
|
175871
|
+
server.once("listening", () => {
|
|
175872
|
+
server.close();
|
|
175873
|
+
resolve2(false);
|
|
175874
|
+
});
|
|
175875
|
+
server.listen(port);
|
|
175876
|
+
});
|
|
175877
|
+
}
|
|
175878
|
+
async function waitForPort(port, timeoutMs = 5000) {
|
|
175879
|
+
const start2 = Date.now();
|
|
175880
|
+
while (await isPortInUse(port)) {
|
|
175881
|
+
if (Date.now() - start2 > timeoutMs) {
|
|
175882
|
+
throw new Error(`Port ${port} is already in use.
|
|
175883
|
+
Stop the other server or specify a different port with --port <number>.`);
|
|
175884
|
+
}
|
|
175885
|
+
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
175886
|
+
}
|
|
175887
|
+
}
|
|
175888
|
+
async function requirePortAvailable(port, timeoutMs = 100) {
|
|
175889
|
+
const start2 = Date.now();
|
|
175890
|
+
while (await isPortInUse(port)) {
|
|
175891
|
+
if (Date.now() - start2 > timeoutMs) {
|
|
175892
|
+
throw new Error(`Port ${port} is already in use.
|
|
175893
|
+
Stop the other server or specify a different port with --port <number>.`);
|
|
175894
|
+
}
|
|
175895
|
+
await new Promise((resolve2) => setTimeout(resolve2, 50));
|
|
175896
|
+
}
|
|
175897
|
+
}
|
|
175687
175898
|
var package_default = {
|
|
175688
175899
|
name: "@playcademy/sandbox",
|
|
175689
|
-
version: "0.
|
|
175900
|
+
version: "0.3.0",
|
|
175690
175901
|
description: "Local development server for Playcademy game development",
|
|
175691
175902
|
type: "module",
|
|
175692
175903
|
exports: {
|
|
@@ -175701,6 +175912,10 @@ var package_default = {
|
|
|
175701
175912
|
"./config": {
|
|
175702
175913
|
import: "./dist/config.js",
|
|
175703
175914
|
types: "./dist/config.d.ts"
|
|
175915
|
+
},
|
|
175916
|
+
"./constants": {
|
|
175917
|
+
import: "./dist/constants.js",
|
|
175918
|
+
types: "./dist/constants.d.ts"
|
|
175704
175919
|
}
|
|
175705
175920
|
},
|
|
175706
175921
|
bin: {
|
|
@@ -178130,7 +178345,7 @@ function sql(strings, ...params) {
|
|
|
178130
178345
|
return new SQL([new StringChunk(str)]);
|
|
178131
178346
|
}
|
|
178132
178347
|
sql22.raw = raw2;
|
|
178133
|
-
function
|
|
178348
|
+
function join22(chunks, separator) {
|
|
178134
178349
|
const result = [];
|
|
178135
178350
|
for (const [i22, chunk] of chunks.entries()) {
|
|
178136
178351
|
if (i22 > 0 && separator !== undefined) {
|
|
@@ -178140,7 +178355,7 @@ function sql(strings, ...params) {
|
|
|
178140
178355
|
}
|
|
178141
178356
|
return new SQL(result);
|
|
178142
178357
|
}
|
|
178143
|
-
sql22.join =
|
|
178358
|
+
sql22.join = join22;
|
|
178144
178359
|
function identifier(value) {
|
|
178145
178360
|
return new Name(value);
|
|
178146
178361
|
}
|
|
@@ -181053,7 +181268,7 @@ class PgSelectQueryBuilderBase extends TypedQueryBuilder {
|
|
|
181053
181268
|
return (table, on) => {
|
|
181054
181269
|
const baseTableName = this.tableName;
|
|
181055
181270
|
const tableName = getTableLikeName(table);
|
|
181056
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
181271
|
+
if (typeof tableName === "string" && this.config.joins?.some((join22) => join22.alias === tableName)) {
|
|
181057
181272
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
181058
181273
|
}
|
|
181059
181274
|
if (!this.isPartialSelect) {
|
|
@@ -181558,7 +181773,7 @@ class PgUpdateBase extends QueryPromise {
|
|
|
181558
181773
|
createJoin(joinType) {
|
|
181559
181774
|
return (table, on) => {
|
|
181560
181775
|
const tableName = getTableLikeName(table);
|
|
181561
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
181776
|
+
if (typeof tableName === "string" && this.config.joins.some((join22) => join22.alias === tableName)) {
|
|
181562
181777
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
181563
181778
|
}
|
|
181564
181779
|
if (typeof on === "function") {
|
|
@@ -181608,10 +181823,10 @@ class PgUpdateBase extends QueryPromise {
|
|
|
181608
181823
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
181609
181824
|
fields[tableName] = fromFields;
|
|
181610
181825
|
}
|
|
181611
|
-
for (const
|
|
181612
|
-
const tableName2 = getTableLikeName(
|
|
181613
|
-
if (typeof tableName2 === "string" && !is(
|
|
181614
|
-
const fromFields = this.getTableLikeFields(
|
|
181826
|
+
for (const join22 of this.config.joins) {
|
|
181827
|
+
const tableName2 = getTableLikeName(join22.table);
|
|
181828
|
+
if (typeof tableName2 === "string" && !is(join22.table, SQL)) {
|
|
181829
|
+
const fromFields = this.getTableLikeFields(join22.table);
|
|
181615
181830
|
fields[tableName2] = fromFields;
|
|
181616
181831
|
}
|
|
181617
181832
|
}
|
|
@@ -182732,217 +182947,59 @@ var notificationsRelations = relations(notifications, ({ one }) => ({
|
|
|
182732
182947
|
references: [users.id]
|
|
182733
182948
|
})
|
|
182734
182949
|
}));
|
|
182735
|
-
|
|
182736
|
-
|
|
182737
|
-
|
|
182738
|
-
player: "00000000-0000-0000-0000-000000000002",
|
|
182739
|
-
developer: "00000000-0000-0000-0000-000000000003",
|
|
182740
|
-
pendingDeveloper: "00000000-0000-0000-0000-000000000004",
|
|
182741
|
-
unverifiedPlayer: "00000000-0000-0000-0000-000000000005"
|
|
182742
|
-
};
|
|
182743
|
-
var DEMO_USERS = {
|
|
182744
|
-
admin: {
|
|
182745
|
-
id: DEMO_USER_IDS.admin,
|
|
182746
|
-
name: "Admin User",
|
|
182747
|
-
username: "admin_user",
|
|
182748
|
-
email: "admin@playcademy.com",
|
|
182749
|
-
emailVerified: true,
|
|
182750
|
-
image: null,
|
|
182751
|
-
role: "admin",
|
|
182752
|
-
developerStatus: "approved",
|
|
182753
|
-
createdAt: now,
|
|
182754
|
-
updatedAt: now
|
|
182755
|
-
},
|
|
182756
|
-
player: {
|
|
182757
|
-
id: DEMO_USER_IDS.player,
|
|
182758
|
-
name: "Player User",
|
|
182759
|
-
username: "player_user",
|
|
182760
|
-
email: "player@playcademy.com",
|
|
182761
|
-
emailVerified: true,
|
|
182762
|
-
image: null,
|
|
182763
|
-
role: "player",
|
|
182764
|
-
developerStatus: "none",
|
|
182765
|
-
createdAt: now,
|
|
182766
|
-
updatedAt: now
|
|
182767
|
-
},
|
|
182768
|
-
developer: {
|
|
182769
|
-
id: DEMO_USER_IDS.developer,
|
|
182770
|
-
name: "Developer User",
|
|
182771
|
-
username: "developer_user",
|
|
182772
|
-
email: "developer@playcademy.com",
|
|
182773
|
-
emailVerified: true,
|
|
182774
|
-
image: null,
|
|
182775
|
-
role: "developer",
|
|
182776
|
-
developerStatus: "approved",
|
|
182777
|
-
createdAt: now,
|
|
182778
|
-
updatedAt: now
|
|
182779
|
-
},
|
|
182780
|
-
pendingDeveloper: {
|
|
182781
|
-
id: DEMO_USER_IDS.pendingDeveloper,
|
|
182782
|
-
name: "Pending Developer",
|
|
182783
|
-
username: "pending_dev",
|
|
182784
|
-
email: "pending@playcademy.com",
|
|
182785
|
-
emailVerified: true,
|
|
182786
|
-
image: null,
|
|
182787
|
-
role: "developer",
|
|
182788
|
-
developerStatus: "pending",
|
|
182789
|
-
createdAt: now,
|
|
182790
|
-
updatedAt: now
|
|
182791
|
-
},
|
|
182792
|
-
unverifiedPlayer: {
|
|
182793
|
-
id: DEMO_USER_IDS.unverifiedPlayer,
|
|
182794
|
-
name: "Unverified Player",
|
|
182795
|
-
username: "unverified_player",
|
|
182796
|
-
email: "unverified@playcademy.com",
|
|
182797
|
-
emailVerified: false,
|
|
182798
|
-
image: null,
|
|
182799
|
-
role: "player",
|
|
182800
|
-
developerStatus: "none",
|
|
182801
|
-
createdAt: now,
|
|
182802
|
-
updatedAt: now
|
|
182950
|
+
function extractBearerToken(authHeader) {
|
|
182951
|
+
if (!authHeader?.startsWith("Bearer ")) {
|
|
182952
|
+
return null;
|
|
182803
182953
|
}
|
|
182804
|
-
|
|
182805
|
-
|
|
182806
|
-
|
|
182807
|
-
|
|
182808
|
-
|
|
182809
|
-
|
|
182810
|
-
|
|
182811
|
-
"sandbox-pending-dev-token": DEMO_USERS.pendingDeveloper,
|
|
182812
|
-
"sandbox-unverified-token": DEMO_USERS.unverifiedPlayer,
|
|
182813
|
-
"mock-game-token-for-local-dev": DEMO_USERS.admin
|
|
182814
|
-
};
|
|
182815
|
-
var MOCK_GAME_ID = "mock-game-id-from-template";
|
|
182816
|
-
var DEMO_ITEM_IDS = {
|
|
182817
|
-
playcademyCredits: "10000000-0000-0000-0000-000000000001",
|
|
182818
|
-
foundingMemberBadge: "10000000-0000-0000-0000-000000000002",
|
|
182819
|
-
earlyAdopterBadge: "10000000-0000-0000-0000-000000000003",
|
|
182820
|
-
firstGameBadge: "10000000-0000-0000-0000-000000000004",
|
|
182821
|
-
commonSword: "10000000-0000-0000-0000-000000000005",
|
|
182822
|
-
smallHealthPotion: "10000000-0000-0000-0000-000000000006",
|
|
182823
|
-
smallBackpack: "10000000-0000-0000-0000-000000000007"
|
|
182824
|
-
};
|
|
182825
|
-
var PLAYCADEMY_CREDITS_ID = DEMO_ITEM_IDS.playcademyCredits;
|
|
182826
|
-
var SAMPLE_ITEMS = [
|
|
182827
|
-
{
|
|
182828
|
-
id: PLAYCADEMY_CREDITS_ID,
|
|
182829
|
-
slug: "PLAYCADEMY_CREDITS",
|
|
182830
|
-
gameId: null,
|
|
182831
|
-
displayName: "PLAYCADEMY credits",
|
|
182832
|
-
description: "The main currency used across PLAYCADEMY.",
|
|
182833
|
-
type: "currency",
|
|
182834
|
-
isPlaceable: false,
|
|
182835
|
-
imageUrl: "http://playcademy-sandbox.local/playcademy-credit.png",
|
|
182836
|
-
metadata: {
|
|
182837
|
-
rarity: "common"
|
|
182838
|
-
}
|
|
182839
|
-
},
|
|
182840
|
-
{
|
|
182841
|
-
id: DEMO_ITEM_IDS.foundingMemberBadge,
|
|
182842
|
-
slug: "FOUNDING_MEMBER_BADGE",
|
|
182843
|
-
gameId: null,
|
|
182844
|
-
displayName: "Founding Member Badge",
|
|
182845
|
-
description: "Reserved for founding core team of the PLAYCADEMY platform.",
|
|
182846
|
-
type: "badge",
|
|
182847
|
-
isPlaceable: false,
|
|
182848
|
-
imageUrl: null,
|
|
182849
|
-
metadata: {
|
|
182850
|
-
rarity: "legendary"
|
|
182954
|
+
return authHeader.substring(7);
|
|
182955
|
+
}
|
|
182956
|
+
function parseSandboxToken(token) {
|
|
182957
|
+
try {
|
|
182958
|
+
const parts2 = token.split(".");
|
|
182959
|
+
if (parts2.length !== 3 || parts2[2] !== "sandbox") {
|
|
182960
|
+
return null;
|
|
182851
182961
|
}
|
|
182852
|
-
|
|
182853
|
-
|
|
182854
|
-
|
|
182855
|
-
slug: "EARLY_ADOPTER_BADGE",
|
|
182856
|
-
gameId: null,
|
|
182857
|
-
displayName: "Early Adopter Badge",
|
|
182858
|
-
description: "Awarded to users who joined during the beta phase.",
|
|
182859
|
-
type: "badge",
|
|
182860
|
-
isPlaceable: false,
|
|
182861
|
-
imageUrl: null,
|
|
182862
|
-
metadata: {
|
|
182863
|
-
rarity: "epic"
|
|
182962
|
+
const header = JSON.parse(atob(parts2[0]));
|
|
182963
|
+
if (header.typ !== "sandbox") {
|
|
182964
|
+
return null;
|
|
182864
182965
|
}
|
|
182865
|
-
|
|
182866
|
-
|
|
182867
|
-
|
|
182868
|
-
slug: "FIRST_GAME_BADGE",
|
|
182869
|
-
gameId: null,
|
|
182870
|
-
displayName: "First Game Played",
|
|
182871
|
-
description: "Awarded for playing your first game in the Playcademy platform.",
|
|
182872
|
-
type: "badge",
|
|
182873
|
-
isPlaceable: false,
|
|
182874
|
-
imageUrl: "http://playcademy-sandbox.local/first-game-badge.png",
|
|
182875
|
-
metadata: {
|
|
182876
|
-
rarity: "uncommon"
|
|
182966
|
+
const payload = JSON.parse(atob(parts2[1]));
|
|
182967
|
+
if (!payload.uid || !payload.sub) {
|
|
182968
|
+
return null;
|
|
182877
182969
|
}
|
|
182878
|
-
|
|
182879
|
-
|
|
182880
|
-
|
|
182881
|
-
|
|
182882
|
-
|
|
182883
|
-
displayName: "Common Sword",
|
|
182884
|
-
description: "A basic sword, good for beginners.",
|
|
182885
|
-
type: "unlock",
|
|
182886
|
-
isPlaceable: false,
|
|
182887
|
-
imageUrl: "http://playcademy-sandbox.local/common-sword.png",
|
|
182888
|
-
metadata: undefined
|
|
182889
|
-
},
|
|
182890
|
-
{
|
|
182891
|
-
id: DEMO_ITEM_IDS.smallHealthPotion,
|
|
182892
|
-
slug: "SMALL_HEALTH_POTION",
|
|
182893
|
-
gameId: null,
|
|
182894
|
-
displayName: "Small Health Potion",
|
|
182895
|
-
description: "Restores a small amount of health.",
|
|
182896
|
-
type: "other",
|
|
182897
|
-
isPlaceable: false,
|
|
182898
|
-
imageUrl: "http://playcademy-sandbox.local/small-health-potion.png",
|
|
182899
|
-
metadata: undefined
|
|
182900
|
-
},
|
|
182901
|
-
{
|
|
182902
|
-
id: DEMO_ITEM_IDS.smallBackpack,
|
|
182903
|
-
slug: "SMALL_BACKPACK",
|
|
182904
|
-
gameId: null,
|
|
182905
|
-
displayName: "Small Backpack",
|
|
182906
|
-
description: "Increases your inventory capacity by 5 slots.",
|
|
182907
|
-
type: "upgrade",
|
|
182908
|
-
isPlaceable: false,
|
|
182909
|
-
imageUrl: "http://playcademy-sandbox.local/small-backpack.png",
|
|
182910
|
-
metadata: undefined
|
|
182911
|
-
}
|
|
182912
|
-
];
|
|
182913
|
-
var SAMPLE_INVENTORY = [
|
|
182914
|
-
{
|
|
182915
|
-
id: "20000000-0000-0000-0000-000000000001",
|
|
182916
|
-
userId: DEMO_USER.id,
|
|
182917
|
-
itemId: PLAYCADEMY_CREDITS_ID,
|
|
182918
|
-
quantity: 1000
|
|
182919
|
-
}
|
|
182920
|
-
];
|
|
182921
|
-
function extractBearerToken(authHeader) {
|
|
182922
|
-
if (!authHeader?.startsWith("Bearer ")) {
|
|
182970
|
+
return {
|
|
182971
|
+
userId: payload.uid,
|
|
182972
|
+
gameSlug: payload.sub
|
|
182973
|
+
};
|
|
182974
|
+
} catch {
|
|
182923
182975
|
return null;
|
|
182924
182976
|
}
|
|
182925
|
-
return authHeader.substring(7);
|
|
182926
182977
|
}
|
|
182927
|
-
function
|
|
182978
|
+
function parseJwtClaims(token) {
|
|
182928
182979
|
try {
|
|
182929
182980
|
const parts2 = token.split(".");
|
|
182930
182981
|
if (parts2.length === 3 && parts2[1]) {
|
|
182931
182982
|
const payload = JSON.parse(atob(parts2[1]));
|
|
182932
|
-
|
|
182983
|
+
if (payload.uid) {
|
|
182984
|
+
return {
|
|
182985
|
+
userId: payload.uid,
|
|
182986
|
+
gameId: payload.sub
|
|
182987
|
+
};
|
|
182988
|
+
}
|
|
182933
182989
|
}
|
|
182934
|
-
} catch
|
|
182935
|
-
console.warn("[Auth] Failed to decode JWT token:", error2);
|
|
182936
|
-
}
|
|
182990
|
+
} catch {}
|
|
182937
182991
|
return null;
|
|
182938
182992
|
}
|
|
182939
|
-
function
|
|
182993
|
+
function resolveAuth(token) {
|
|
182940
182994
|
const demoUser = DEMO_TOKENS[token];
|
|
182941
|
-
if (demoUser)
|
|
182942
|
-
return demoUser.id;
|
|
182943
|
-
}
|
|
182995
|
+
if (demoUser)
|
|
182996
|
+
return { userId: demoUser.id };
|
|
182944
182997
|
if (token.includes(".")) {
|
|
182945
|
-
|
|
182998
|
+
const sandboxClaims = parseSandboxToken(token);
|
|
182999
|
+
if (sandboxClaims) {
|
|
183000
|
+
return sandboxClaims;
|
|
183001
|
+
}
|
|
183002
|
+
return parseJwtClaims(token);
|
|
182946
183003
|
}
|
|
182947
183004
|
return null;
|
|
182948
183005
|
}
|
|
@@ -182957,6 +183014,18 @@ async function fetchUserFromDatabase(db, userId) {
|
|
|
182957
183014
|
throw error2;
|
|
182958
183015
|
}
|
|
182959
183016
|
}
|
|
183017
|
+
async function resolveGameIdFromSlug(db, slug) {
|
|
183018
|
+
try {
|
|
183019
|
+
const game = await db.query.games.findFirst({
|
|
183020
|
+
where: eq(games.slug, slug),
|
|
183021
|
+
columns: { id: true }
|
|
183022
|
+
});
|
|
183023
|
+
return game?.id || null;
|
|
183024
|
+
} catch (error2) {
|
|
183025
|
+
console.error("[Auth] Error looking up game by slug:", error2);
|
|
183026
|
+
return null;
|
|
183027
|
+
}
|
|
183028
|
+
}
|
|
182960
183029
|
function isPublicRoute(path4, exceptions) {
|
|
182961
183030
|
return exceptions.some((exception) => {
|
|
182962
183031
|
if (path4 === exception)
|
|
@@ -182978,11 +183047,11 @@ async function authenticateRequest(c3) {
|
|
|
182978
183047
|
shouldReturn404: true
|
|
182979
183048
|
};
|
|
182980
183049
|
}
|
|
182981
|
-
let
|
|
183050
|
+
let claims;
|
|
182982
183051
|
if (apiKey && !bearerToken) {
|
|
182983
|
-
|
|
183052
|
+
claims = { userId: DEMO_USERS.admin.id };
|
|
182984
183053
|
} else {
|
|
182985
|
-
const resolved =
|
|
183054
|
+
const resolved = resolveAuth(token);
|
|
182986
183055
|
if (!resolved) {
|
|
182987
183056
|
return {
|
|
182988
183057
|
success: false,
|
|
@@ -182990,26 +183059,22 @@ async function authenticateRequest(c3) {
|
|
|
182990
183059
|
shouldReturn404: true
|
|
182991
183060
|
};
|
|
182992
183061
|
}
|
|
182993
|
-
|
|
183062
|
+
claims = resolved;
|
|
182994
183063
|
}
|
|
182995
183064
|
const db = c3.get("db");
|
|
182996
183065
|
if (!db) {
|
|
182997
183066
|
console.error("[Auth] Database not available in context");
|
|
182998
|
-
return {
|
|
182999
|
-
success: false,
|
|
183000
|
-
error: "Internal server error",
|
|
183001
|
-
shouldReturn404: false
|
|
183002
|
-
};
|
|
183067
|
+
return { success: false, error: "Internal server error", shouldReturn404: false };
|
|
183003
183068
|
}
|
|
183004
|
-
const user = await fetchUserFromDatabase(db,
|
|
183069
|
+
const user = await fetchUserFromDatabase(db, claims.userId);
|
|
183005
183070
|
if (!user) {
|
|
183006
|
-
return {
|
|
183007
|
-
success: false,
|
|
183008
|
-
error: "User not found or token invalid",
|
|
183009
|
-
shouldReturn404: true
|
|
183010
|
-
};
|
|
183071
|
+
return { success: false, error: "User not found or token invalid", shouldReturn404: true };
|
|
183011
183072
|
}
|
|
183012
|
-
|
|
183073
|
+
let gameId = claims.gameId;
|
|
183074
|
+
if (!gameId && claims.gameSlug) {
|
|
183075
|
+
gameId = await resolveGameIdFromSlug(db, claims.gameSlug) ?? undefined;
|
|
183076
|
+
}
|
|
183077
|
+
return { success: true, user, gameId };
|
|
183013
183078
|
}
|
|
183014
183079
|
function setupAuth(options = {}) {
|
|
183015
183080
|
const { exceptions = [] } = options;
|
|
@@ -183021,6 +183086,8 @@ function setupAuth(options = {}) {
|
|
|
183021
183086
|
const result = await authenticateRequest(c3);
|
|
183022
183087
|
if (result.success) {
|
|
183023
183088
|
c3.set("user", result.user);
|
|
183089
|
+
if (result.gameId)
|
|
183090
|
+
c3.set("gameId", result.gameId);
|
|
183024
183091
|
await next();
|
|
183025
183092
|
return;
|
|
183026
183093
|
}
|
|
@@ -188861,31 +188928,31 @@ function getDatabase() {
|
|
|
188861
188928
|
}
|
|
188862
188929
|
|
|
188863
188930
|
class DatabasePathManager {
|
|
188864
|
-
static DEFAULT_DB_SUBPATH =
|
|
188931
|
+
static DEFAULT_DB_SUBPATH = join3("@playcademy", "vite-plugin", "node_modules", ".playcademy", "sandbox.db");
|
|
188865
188932
|
static findNodeModulesPath() {
|
|
188866
188933
|
let currentDir = process.cwd();
|
|
188867
188934
|
while (currentDir !== dirname(currentDir)) {
|
|
188868
|
-
const nodeModulesPath =
|
|
188935
|
+
const nodeModulesPath = join3(currentDir, "node_modules");
|
|
188869
188936
|
if (fs22.existsSync(nodeModulesPath)) {
|
|
188870
188937
|
return nodeModulesPath;
|
|
188871
188938
|
}
|
|
188872
188939
|
currentDir = dirname(currentDir);
|
|
188873
188940
|
}
|
|
188874
|
-
return
|
|
188941
|
+
return join3(process.cwd(), "node_modules");
|
|
188875
188942
|
}
|
|
188876
188943
|
static resolveDatabasePath(customPath) {
|
|
188877
188944
|
if (customPath) {
|
|
188878
188945
|
if (customPath === ":memory:")
|
|
188879
188946
|
return ":memory:";
|
|
188880
|
-
return isAbsolute(customPath) ? customPath :
|
|
188947
|
+
return isAbsolute(customPath) ? customPath : join3(process.cwd(), customPath);
|
|
188881
188948
|
}
|
|
188882
|
-
return
|
|
188949
|
+
return join3(this.findNodeModulesPath(), this.DEFAULT_DB_SUBPATH);
|
|
188883
188950
|
}
|
|
188884
188951
|
static ensureDatabaseDirectory(dbPath) {
|
|
188885
188952
|
if (dbPath === ":memory:")
|
|
188886
188953
|
return;
|
|
188887
188954
|
const dirPath = dirname(dbPath);
|
|
188888
|
-
const absolutePath = isAbsolute(dirPath) ? dirPath :
|
|
188955
|
+
const absolutePath = isAbsolute(dirPath) ? dirPath : join3(process.cwd(), dirPath);
|
|
188889
188956
|
try {
|
|
188890
188957
|
if (!fs22.existsSync(absolutePath)) {
|
|
188891
188958
|
fs22.mkdirSync(absolutePath, { recursive: true });
|
|
@@ -189196,7 +189263,51 @@ var init_overworld = __esm3(() => {
|
|
|
189196
189263
|
FIRST_GAME: ITEM_SLUGS2.FIRST_GAME_BADGE
|
|
189197
189264
|
};
|
|
189198
189265
|
});
|
|
189199
|
-
var
|
|
189266
|
+
var TIMEBACK_ORG_SOURCED_ID = "PLAYCADEMY";
|
|
189267
|
+
var TIMEBACK_ORG_NAME = "Playcademy Studios";
|
|
189268
|
+
var TIMEBACK_ORG_TYPE = "department";
|
|
189269
|
+
var TIMEBACK_COURSE_DEFAULTS;
|
|
189270
|
+
var TIMEBACK_RESOURCE_DEFAULTS;
|
|
189271
|
+
var TIMEBACK_COMPONENT_DEFAULTS;
|
|
189272
|
+
var TIMEBACK_COMPONENT_RESOURCE_DEFAULTS;
|
|
189273
|
+
var init_timeback = __esm3(() => {
|
|
189274
|
+
TIMEBACK_COURSE_DEFAULTS = {
|
|
189275
|
+
gradingScheme: "STANDARD",
|
|
189276
|
+
level: {
|
|
189277
|
+
elementary: "Elementary",
|
|
189278
|
+
middle: "Middle",
|
|
189279
|
+
high: "High",
|
|
189280
|
+
ap: "AP"
|
|
189281
|
+
},
|
|
189282
|
+
goals: {
|
|
189283
|
+
dailyXp: 50,
|
|
189284
|
+
dailyLessons: 3
|
|
189285
|
+
},
|
|
189286
|
+
metrics: {
|
|
189287
|
+
totalXp: 1000,
|
|
189288
|
+
totalLessons: 50
|
|
189289
|
+
}
|
|
189290
|
+
};
|
|
189291
|
+
TIMEBACK_RESOURCE_DEFAULTS = {
|
|
189292
|
+
vendorId: "playcademy",
|
|
189293
|
+
roles: ["primary"],
|
|
189294
|
+
importance: "primary",
|
|
189295
|
+
metadata: {
|
|
189296
|
+
type: "interactive",
|
|
189297
|
+
toolProvider: "Playcademy",
|
|
189298
|
+
instructionalMethod: "exploratory",
|
|
189299
|
+
language: "en-US"
|
|
189300
|
+
}
|
|
189301
|
+
};
|
|
189302
|
+
TIMEBACK_COMPONENT_DEFAULTS = {
|
|
189303
|
+
sortOrder: 1,
|
|
189304
|
+
prerequisiteCriteria: "ALL"
|
|
189305
|
+
};
|
|
189306
|
+
TIMEBACK_COMPONENT_RESOURCE_DEFAULTS = {
|
|
189307
|
+
sortOrder: 1,
|
|
189308
|
+
lessonType: "quiz"
|
|
189309
|
+
};
|
|
189310
|
+
});
|
|
189200
189311
|
var init_workers = () => {};
|
|
189201
189312
|
var init_src2 = __esm3(() => {
|
|
189202
189313
|
init_auth();
|
|
@@ -189237,7 +189348,6 @@ var HTTP_DEFAULTS;
|
|
|
189237
189348
|
var AUTH_DEFAULTS;
|
|
189238
189349
|
var CACHE_DEFAULTS;
|
|
189239
189350
|
var CONFIG_DEFAULTS;
|
|
189240
|
-
var DEFAULT_PLAYCADEMY_ORGANIZATION_ID;
|
|
189241
189351
|
var PLAYCADEMY_DEFAULTS;
|
|
189242
189352
|
var RESOURCE_DEFAULTS;
|
|
189243
189353
|
var HTTP_STATUS;
|
|
@@ -189384,54 +189494,26 @@ var init_constants = __esm3(() => {
|
|
|
189384
189494
|
CONFIG_DEFAULTS = {
|
|
189385
189495
|
fileNames: ["timeback.config.js", "timeback.config.json"]
|
|
189386
189496
|
};
|
|
189387
|
-
DEFAULT_PLAYCADEMY_ORGANIZATION_ID = process.env.TIMEBACK_ORG_SOURCE_ID || "PLAYCADEMY";
|
|
189388
189497
|
PLAYCADEMY_DEFAULTS = {
|
|
189389
|
-
organization:
|
|
189498
|
+
organization: TIMEBACK_ORG_SOURCED_ID,
|
|
189390
189499
|
launchBaseUrls: PLAYCADEMY_BASE_URLS
|
|
189391
189500
|
};
|
|
189392
189501
|
RESOURCE_DEFAULTS = {
|
|
189393
189502
|
organization: {
|
|
189394
|
-
name:
|
|
189395
|
-
type:
|
|
189503
|
+
name: TIMEBACK_ORG_NAME,
|
|
189504
|
+
type: TIMEBACK_ORG_TYPE
|
|
189396
189505
|
},
|
|
189397
189506
|
course: {
|
|
189398
|
-
gradingScheme:
|
|
189399
|
-
level:
|
|
189400
|
-
elementary: "Elementary",
|
|
189401
|
-
middle: "Middle",
|
|
189402
|
-
high: "High",
|
|
189403
|
-
ap: "AP"
|
|
189404
|
-
},
|
|
189507
|
+
gradingScheme: TIMEBACK_COURSE_DEFAULTS.gradingScheme,
|
|
189508
|
+
level: TIMEBACK_COURSE_DEFAULTS.level,
|
|
189405
189509
|
metadata: {
|
|
189406
|
-
goals:
|
|
189407
|
-
|
|
189408
|
-
dailyLessons: 3
|
|
189409
|
-
},
|
|
189410
|
-
metrics: {
|
|
189411
|
-
totalXp: 1000,
|
|
189412
|
-
totalLessons: 50
|
|
189413
|
-
}
|
|
189510
|
+
goals: TIMEBACK_COURSE_DEFAULTS.goals,
|
|
189511
|
+
metrics: TIMEBACK_COURSE_DEFAULTS.metrics
|
|
189414
189512
|
}
|
|
189415
189513
|
},
|
|
189416
|
-
component:
|
|
189417
|
-
|
|
189418
|
-
|
|
189419
|
-
},
|
|
189420
|
-
resource: {
|
|
189421
|
-
vendorId: "playcademy",
|
|
189422
|
-
roles: ["primary"],
|
|
189423
|
-
importance: "primary",
|
|
189424
|
-
metadata: {
|
|
189425
|
-
type: "interactive",
|
|
189426
|
-
toolProvider: "Playcademy",
|
|
189427
|
-
instructionalMethod: "exploratory",
|
|
189428
|
-
language: "en-US"
|
|
189429
|
-
}
|
|
189430
|
-
},
|
|
189431
|
-
componentResource: {
|
|
189432
|
-
sortOrder: 1,
|
|
189433
|
-
lessonType: "quiz"
|
|
189434
|
-
}
|
|
189514
|
+
component: TIMEBACK_COMPONENT_DEFAULTS,
|
|
189515
|
+
resource: TIMEBACK_RESOURCE_DEFAULTS,
|
|
189516
|
+
componentResource: TIMEBACK_COMPONENT_RESOURCE_DEFAULTS
|
|
189435
189517
|
};
|
|
189436
189518
|
HTTP_STATUS = {
|
|
189437
189519
|
CLIENT_ERROR_MIN: 400,
|
|
@@ -195440,7 +195522,8 @@ class TimebackClient {
|
|
|
195440
195522
|
courseId: enrollment.course.id,
|
|
195441
195523
|
status: "active",
|
|
195442
195524
|
grades,
|
|
195443
|
-
subjects
|
|
195525
|
+
subjects,
|
|
195526
|
+
school: enrollment.school
|
|
195444
195527
|
};
|
|
195445
195528
|
});
|
|
195446
195529
|
this.cacheManager.setEnrollments(studentId, enrollments);
|
|
@@ -195511,7 +195594,51 @@ var init_overworld2 = __esm4(() => {
|
|
|
195511
195594
|
FIRST_GAME: ITEM_SLUGS3.FIRST_GAME_BADGE
|
|
195512
195595
|
};
|
|
195513
195596
|
});
|
|
195514
|
-
var
|
|
195597
|
+
var TIMEBACK_ORG_SOURCED_ID2 = "PLAYCADEMY";
|
|
195598
|
+
var TIMEBACK_ORG_NAME2 = "Playcademy Studios";
|
|
195599
|
+
var TIMEBACK_ORG_TYPE2 = "department";
|
|
195600
|
+
var TIMEBACK_COURSE_DEFAULTS2;
|
|
195601
|
+
var TIMEBACK_RESOURCE_DEFAULTS2;
|
|
195602
|
+
var TIMEBACK_COMPONENT_DEFAULTS2;
|
|
195603
|
+
var TIMEBACK_COMPONENT_RESOURCE_DEFAULTS2;
|
|
195604
|
+
var init_timeback2 = __esm4(() => {
|
|
195605
|
+
TIMEBACK_COURSE_DEFAULTS2 = {
|
|
195606
|
+
gradingScheme: "STANDARD",
|
|
195607
|
+
level: {
|
|
195608
|
+
elementary: "Elementary",
|
|
195609
|
+
middle: "Middle",
|
|
195610
|
+
high: "High",
|
|
195611
|
+
ap: "AP"
|
|
195612
|
+
},
|
|
195613
|
+
goals: {
|
|
195614
|
+
dailyXp: 50,
|
|
195615
|
+
dailyLessons: 3
|
|
195616
|
+
},
|
|
195617
|
+
metrics: {
|
|
195618
|
+
totalXp: 1000,
|
|
195619
|
+
totalLessons: 50
|
|
195620
|
+
}
|
|
195621
|
+
};
|
|
195622
|
+
TIMEBACK_RESOURCE_DEFAULTS2 = {
|
|
195623
|
+
vendorId: "playcademy",
|
|
195624
|
+
roles: ["primary"],
|
|
195625
|
+
importance: "primary",
|
|
195626
|
+
metadata: {
|
|
195627
|
+
type: "interactive",
|
|
195628
|
+
toolProvider: "Playcademy",
|
|
195629
|
+
instructionalMethod: "exploratory",
|
|
195630
|
+
language: "en-US"
|
|
195631
|
+
}
|
|
195632
|
+
};
|
|
195633
|
+
TIMEBACK_COMPONENT_DEFAULTS2 = {
|
|
195634
|
+
sortOrder: 1,
|
|
195635
|
+
prerequisiteCriteria: "ALL"
|
|
195636
|
+
};
|
|
195637
|
+
TIMEBACK_COMPONENT_RESOURCE_DEFAULTS2 = {
|
|
195638
|
+
sortOrder: 1,
|
|
195639
|
+
lessonType: "quiz"
|
|
195640
|
+
};
|
|
195641
|
+
});
|
|
195515
195642
|
var init_workers2 = () => {};
|
|
195516
195643
|
var init_src3 = __esm4(() => {
|
|
195517
195644
|
init_auth2();
|
|
@@ -195543,7 +195670,6 @@ var HTTP_DEFAULTS2;
|
|
|
195543
195670
|
var AUTH_DEFAULTS2;
|
|
195544
195671
|
var CACHE_DEFAULTS2;
|
|
195545
195672
|
var CONFIG_DEFAULTS2;
|
|
195546
|
-
var DEFAULT_PLAYCADEMY_ORGANIZATION_ID2;
|
|
195547
195673
|
var PLAYCADEMY_DEFAULTS2;
|
|
195548
195674
|
var RESOURCE_DEFAULTS2;
|
|
195549
195675
|
var HTTP_STATUS2;
|
|
@@ -195690,54 +195816,26 @@ var init_constants2 = __esm4(() => {
|
|
|
195690
195816
|
CONFIG_DEFAULTS2 = {
|
|
195691
195817
|
fileNames: ["timeback.config.js", "timeback.config.json"]
|
|
195692
195818
|
};
|
|
195693
|
-
DEFAULT_PLAYCADEMY_ORGANIZATION_ID2 = process.env.TIMEBACK_ORG_SOURCE_ID || "PLAYCADEMY";
|
|
195694
195819
|
PLAYCADEMY_DEFAULTS2 = {
|
|
195695
|
-
organization:
|
|
195820
|
+
organization: TIMEBACK_ORG_SOURCED_ID2,
|
|
195696
195821
|
launchBaseUrls: PLAYCADEMY_BASE_URLS2
|
|
195697
195822
|
};
|
|
195698
195823
|
RESOURCE_DEFAULTS2 = {
|
|
195699
195824
|
organization: {
|
|
195700
|
-
name:
|
|
195701
|
-
type:
|
|
195825
|
+
name: TIMEBACK_ORG_NAME2,
|
|
195826
|
+
type: TIMEBACK_ORG_TYPE2
|
|
195702
195827
|
},
|
|
195703
195828
|
course: {
|
|
195704
|
-
gradingScheme:
|
|
195705
|
-
level:
|
|
195706
|
-
elementary: "Elementary",
|
|
195707
|
-
middle: "Middle",
|
|
195708
|
-
high: "High",
|
|
195709
|
-
ap: "AP"
|
|
195710
|
-
},
|
|
195711
|
-
metadata: {
|
|
195712
|
-
goals: {
|
|
195713
|
-
dailyXp: 50,
|
|
195714
|
-
dailyLessons: 3
|
|
195715
|
-
},
|
|
195716
|
-
metrics: {
|
|
195717
|
-
totalXp: 1000,
|
|
195718
|
-
totalLessons: 50
|
|
195719
|
-
}
|
|
195720
|
-
}
|
|
195721
|
-
},
|
|
195722
|
-
component: {
|
|
195723
|
-
sortOrder: 1,
|
|
195724
|
-
prerequisiteCriteria: "ALL"
|
|
195725
|
-
},
|
|
195726
|
-
resource: {
|
|
195727
|
-
vendorId: "playcademy",
|
|
195728
|
-
roles: ["primary"],
|
|
195729
|
-
importance: "primary",
|
|
195829
|
+
gradingScheme: TIMEBACK_COURSE_DEFAULTS2.gradingScheme,
|
|
195830
|
+
level: TIMEBACK_COURSE_DEFAULTS2.level,
|
|
195730
195831
|
metadata: {
|
|
195731
|
-
|
|
195732
|
-
|
|
195733
|
-
instructionalMethod: "exploratory",
|
|
195734
|
-
language: "en-US"
|
|
195832
|
+
goals: TIMEBACK_COURSE_DEFAULTS2.goals,
|
|
195833
|
+
metrics: TIMEBACK_COURSE_DEFAULTS2.metrics
|
|
195735
195834
|
}
|
|
195736
195835
|
},
|
|
195737
|
-
|
|
195738
|
-
|
|
195739
|
-
|
|
195740
|
-
}
|
|
195836
|
+
component: TIMEBACK_COMPONENT_DEFAULTS2,
|
|
195837
|
+
resource: TIMEBACK_RESOURCE_DEFAULTS2,
|
|
195838
|
+
componentResource: TIMEBACK_COMPONENT_RESOURCE_DEFAULTS2
|
|
195741
195839
|
};
|
|
195742
195840
|
HTTP_STATUS2 = {
|
|
195743
195841
|
CLIENT_ERROR_MIN: 400,
|
|
@@ -196079,66 +196177,87 @@ function buildResourceMetadata({
|
|
|
196079
196177
|
return metadata2;
|
|
196080
196178
|
}
|
|
196081
196179
|
init_src();
|
|
196082
|
-
async function
|
|
196083
|
-
|
|
196084
|
-
|
|
196085
|
-
|
|
196086
|
-
const
|
|
196087
|
-
|
|
196088
|
-
|
|
196089
|
-
|
|
196090
|
-
|
|
196091
|
-
|
|
196092
|
-
|
|
196180
|
+
async function fetchStudentFromOneRoster(timebackId) {
|
|
196181
|
+
log2.debug("[OneRoster] Fetching student profile", { timebackId });
|
|
196182
|
+
try {
|
|
196183
|
+
const client2 = await getTimebackClient();
|
|
196184
|
+
const user = await client2.oneroster.users.get(timebackId);
|
|
196185
|
+
const primaryRoleEntry = user.roles.find((r22) => r22.roleType === "primary");
|
|
196186
|
+
const role = primaryRoleEntry?.role ?? user.roles[0]?.role ?? "student";
|
|
196187
|
+
const orgMap = new Map;
|
|
196188
|
+
if (user.primaryOrg) {
|
|
196189
|
+
orgMap.set(user.primaryOrg.sourcedId, {
|
|
196190
|
+
id: user.primaryOrg.sourcedId,
|
|
196191
|
+
name: user.primaryOrg.name ?? null,
|
|
196192
|
+
type: user.primaryOrg.type || "school",
|
|
196193
|
+
isPrimary: true
|
|
196194
|
+
});
|
|
196195
|
+
}
|
|
196196
|
+
for (const r22 of user.roles) {
|
|
196197
|
+
if (r22.org && !orgMap.has(r22.org.sourcedId)) {
|
|
196198
|
+
orgMap.set(r22.org.sourcedId, {
|
|
196199
|
+
id: r22.org.sourcedId,
|
|
196200
|
+
name: null,
|
|
196201
|
+
type: "school",
|
|
196202
|
+
isPrimary: false
|
|
196203
|
+
});
|
|
196204
|
+
}
|
|
196205
|
+
}
|
|
196206
|
+
const organizations = Array.from(orgMap.values());
|
|
196207
|
+
return { role, organizations };
|
|
196208
|
+
} catch (error2) {
|
|
196209
|
+
log2.warn("[OneRoster] Failed to fetch student, using defaults", { error: error2, timebackId });
|
|
196210
|
+
return { role: "student", organizations: [] };
|
|
196093
196211
|
}
|
|
196094
|
-
|
|
196212
|
+
}
|
|
196213
|
+
async function fetchEnrollmentsFromEduBridge(timebackId) {
|
|
196214
|
+
const db = getDatabase();
|
|
196215
|
+
log2.debug("[EduBridge] Fetching student enrollments", { timebackId });
|
|
196095
196216
|
try {
|
|
196096
196217
|
const client2 = await getTimebackClient();
|
|
196097
|
-
const
|
|
196098
|
-
const courseIds =
|
|
196099
|
-
if (courseIds.length === 0)
|
|
196218
|
+
const enrollments = await client2.getEnrollments(timebackId);
|
|
196219
|
+
const courseIds = enrollments.map((e2) => e2.courseId).filter((id) => Boolean(id));
|
|
196220
|
+
if (courseIds.length === 0)
|
|
196100
196221
|
return [];
|
|
196101
|
-
|
|
196222
|
+
const courseToSchool = new Map(enrollments.filter((e2) => e2.school?.id).map((e2) => [e2.courseId, e2.school.id]));
|
|
196102
196223
|
const integrations = await db.query.gameTimebackIntegrations.findMany({
|
|
196103
196224
|
where: inArray(gameTimebackIntegrations.courseId, courseIds)
|
|
196104
196225
|
});
|
|
196105
|
-
return integrations.map((
|
|
196106
|
-
gameId:
|
|
196107
|
-
grade:
|
|
196108
|
-
subject:
|
|
196109
|
-
courseId:
|
|
196226
|
+
return integrations.map((i32) => ({
|
|
196227
|
+
gameId: i32.gameId,
|
|
196228
|
+
grade: i32.grade,
|
|
196229
|
+
subject: i32.subject,
|
|
196230
|
+
courseId: i32.courseId,
|
|
196231
|
+
orgId: courseToSchool.get(i32.courseId)
|
|
196110
196232
|
}));
|
|
196111
196233
|
} catch (error2) {
|
|
196112
|
-
log2.warn("[
|
|
196113
|
-
error: error2,
|
|
196114
|
-
timebackId
|
|
196115
|
-
});
|
|
196234
|
+
log2.warn("[EduBridge] Failed to fetch enrollments", { error: error2, timebackId });
|
|
196116
196235
|
return [];
|
|
196117
196236
|
}
|
|
196118
196237
|
}
|
|
196119
|
-
|
|
196120
|
-
|
|
196121
|
-
|
|
196122
|
-
|
|
196123
|
-
|
|
196124
|
-
|
|
196125
|
-
|
|
196126
|
-
|
|
196127
|
-
return role;
|
|
196128
|
-
} catch (error2) {
|
|
196129
|
-
log2.warn("[timeback] Failed to fetch user role, defaulting to student:", {
|
|
196130
|
-
error: error2,
|
|
196131
|
-
timebackId
|
|
196132
|
-
});
|
|
196133
|
-
return "student";
|
|
196134
|
-
}
|
|
196238
|
+
function filterEnrollmentsByGame(enrollments, gameId) {
|
|
196239
|
+
return enrollments.filter((e2) => e2.gameId === gameId).map(({ gameId: _42, ...rest }) => rest);
|
|
196240
|
+
}
|
|
196241
|
+
function filterOrganizationsByEnrollments(organizations, enrollments) {
|
|
196242
|
+
const enrollmentOrgIds = new Set(enrollments.map((e2) => e2.orgId).filter(Boolean));
|
|
196243
|
+
if (enrollmentOrgIds.size === 0)
|
|
196244
|
+
return [];
|
|
196245
|
+
return organizations.filter((o42) => enrollmentOrgIds.has(o42.id));
|
|
196135
196246
|
}
|
|
196136
|
-
async function fetchUserTimebackData(timebackId) {
|
|
196137
|
-
const [role,
|
|
196138
|
-
|
|
196139
|
-
|
|
196247
|
+
async function fetchUserTimebackData(timebackId, gameId) {
|
|
196248
|
+
const [{ role, organizations: allOrganizations }, allEnrollments] = await Promise.all([
|
|
196249
|
+
fetchStudentFromOneRoster(timebackId),
|
|
196250
|
+
fetchEnrollmentsFromEduBridge(timebackId)
|
|
196140
196251
|
]);
|
|
196141
|
-
|
|
196252
|
+
const enrollments = gameId ? filterEnrollmentsByGame(allEnrollments, gameId) : allEnrollments;
|
|
196253
|
+
const organizations = gameId ? filterOrganizationsByEnrollments(allOrganizations, enrollments) : allOrganizations;
|
|
196254
|
+
log2.debug("[Timeback] Fetched student data", {
|
|
196255
|
+
timebackId,
|
|
196256
|
+
role,
|
|
196257
|
+
enrollments: enrollments.map((e2) => `${e2.subject}:${e2.grade}`),
|
|
196258
|
+
organizations: organizations.map((o42) => `${o42.name ?? o42.id} (${o42.type})`)
|
|
196259
|
+
});
|
|
196260
|
+
return { id: timebackId, role, enrollments, organizations };
|
|
196142
196261
|
}
|
|
196143
196262
|
var AchievementCompletionType;
|
|
196144
196263
|
((AchievementCompletionType2) => {
|
|
@@ -198546,7 +198665,7 @@ async function scanAssetDirectory(distPath) {
|
|
|
198546
198665
|
async function scanFiles(dir, baseDir = dir) {
|
|
198547
198666
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
198548
198667
|
for (const entry of entries) {
|
|
198549
|
-
const fullPath =
|
|
198668
|
+
const fullPath = join4(dir, entry.name);
|
|
198550
198669
|
if (entry.isDirectory()) {
|
|
198551
198670
|
await scanFiles(fullPath, baseDir);
|
|
198552
198671
|
} else {
|
|
@@ -198912,7 +199031,7 @@ class CloudflareProvider {
|
|
|
198912
199031
|
async function scanDirectory(dir) {
|
|
198913
199032
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
198914
199033
|
for (const entry of entries) {
|
|
198915
|
-
const fullPath =
|
|
199034
|
+
const fullPath = join5(dir, entry.name);
|
|
198916
199035
|
if (entry.isDirectory()) {
|
|
198917
199036
|
if (await scanDirectory(fullPath))
|
|
198918
199037
|
return true;
|
|
@@ -198934,7 +199053,7 @@ class CloudflareProvider {
|
|
|
198934
199053
|
async resolveAssetBasePath(dirPath) {
|
|
198935
199054
|
const entries = await readdir2(dirPath, { withFileTypes: true });
|
|
198936
199055
|
if (entries.length === 1 && entries[0]?.isDirectory()) {
|
|
198937
|
-
const unwrappedPath =
|
|
199056
|
+
const unwrappedPath = join5(dirPath, entries[0].name);
|
|
198938
199057
|
log2.debug("[CloudflareProvider] Unwrapping wrapper directory", {
|
|
198939
199058
|
wrapper: entries[0].name
|
|
198940
199059
|
});
|
|
@@ -198945,7 +199064,7 @@ class CloudflareProvider {
|
|
|
198945
199064
|
async uploadFilesToR2(dir, baseDir, bucketName) {
|
|
198946
199065
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
198947
199066
|
for (const entry of entries) {
|
|
198948
|
-
const fullPath =
|
|
199067
|
+
const fullPath = join5(dir, entry.name);
|
|
198949
199068
|
if (entry.isDirectory()) {
|
|
198950
199069
|
await this.uploadFilesToR2(fullPath, baseDir, bucketName);
|
|
198951
199070
|
} else {
|
|
@@ -199422,38 +199541,18 @@ async function seedCurrencies(db) {
|
|
|
199422
199541
|
});
|
|
199423
199542
|
}
|
|
199424
199543
|
}
|
|
199425
|
-
|
|
199426
|
-
|
|
199427
|
-
customLogger = logger3;
|
|
199544
|
+
function generateMockStudentId(userId) {
|
|
199545
|
+
return `mock-student-${userId.slice(-8)}`;
|
|
199428
199546
|
}
|
|
199429
|
-
function
|
|
199430
|
-
|
|
199431
|
-
|
|
199432
|
-
}
|
|
199433
|
-
return {
|
|
199434
|
-
info: (msg) => console.log(msg),
|
|
199435
|
-
warn: (msg) => console.warn(msg),
|
|
199436
|
-
error: (msg) => console.error(msg)
|
|
199437
|
-
};
|
|
199438
|
-
}
|
|
199439
|
-
var logger3 = {
|
|
199440
|
-
info: (msg) => {
|
|
199441
|
-
if (customLogger || !config.embedded) {
|
|
199442
|
-
getLogger().info(msg);
|
|
199443
|
-
}
|
|
199444
|
-
},
|
|
199445
|
-
warn: (msg) => getLogger().warn(msg),
|
|
199446
|
-
error: (msg) => getLogger().error(msg)
|
|
199447
|
-
};
|
|
199448
|
-
function resolveStudentId(studentId) {
|
|
199449
|
-
if (!studentId)
|
|
199547
|
+
function generateTimebackId(userId, isPrimaryUser = false) {
|
|
199548
|
+
const timebackId = config.timeback.timebackId;
|
|
199549
|
+
if (!timebackId) {
|
|
199450
199550
|
return null;
|
|
199451
|
-
|
|
199452
|
-
|
|
199453
|
-
|
|
199454
|
-
}
|
|
199455
|
-
|
|
199456
|
-
return resolveStudentId(config.timeback.studentId);
|
|
199551
|
+
}
|
|
199552
|
+
if (timebackId === "mock") {
|
|
199553
|
+
return generateMockStudentId(userId);
|
|
199554
|
+
}
|
|
199555
|
+
return isPrimaryUser ? timebackId : generateMockStudentId(userId);
|
|
199457
199556
|
}
|
|
199458
199557
|
async function seedTimebackIntegrations(db, gameId, courses) {
|
|
199459
199558
|
const now2 = new Date;
|
|
@@ -199477,12 +199576,10 @@ async function seedTimebackIntegrations(db, gameId, courses) {
|
|
|
199477
199576
|
});
|
|
199478
199577
|
seededCount++;
|
|
199479
199578
|
} catch (error2) {
|
|
199480
|
-
console.error(`❌ Error seeding
|
|
199579
|
+
console.error(`❌ Error seeding Timeback integration for ${course.subject}:${course.grade}:`, error2);
|
|
199481
199580
|
}
|
|
199482
199581
|
}
|
|
199483
|
-
|
|
199484
|
-
logger3.info(`\uD83D\uDCDA Seeded ${seededCount} TimeBack integration(s)`);
|
|
199485
|
-
}
|
|
199582
|
+
return seededCount;
|
|
199486
199583
|
}
|
|
199487
199584
|
async function seedCoreGames(db) {
|
|
199488
199585
|
const now2 = new Date;
|
|
@@ -199516,7 +199613,6 @@ async function seedCurrentProjectGame(db, project) {
|
|
|
199516
199613
|
where: (games3, { eq: eq3 }) => eq3(games3.slug, project.slug)
|
|
199517
199614
|
});
|
|
199518
199615
|
if (existingGame) {
|
|
199519
|
-
logger3.info(`\uD83C\uDFAE Game "${project.displayName}" (${project.slug}) already exists`);
|
|
199520
199616
|
if (project.timebackCourses && project.timebackCourses.length > 0) {
|
|
199521
199617
|
await seedTimebackIntegrations(db, existingGame.id, project.timebackCourses);
|
|
199522
199618
|
}
|
|
@@ -199603,11 +199699,12 @@ async function seedSpriteTemplates(db) {
|
|
|
199603
199699
|
}
|
|
199604
199700
|
async function seedDemoData(db) {
|
|
199605
199701
|
try {
|
|
199606
|
-
const
|
|
199607
|
-
for (const
|
|
199702
|
+
const primaryUserId = DEMO_USERS.player.id;
|
|
199703
|
+
for (const user of Object.values(DEMO_USERS)) {
|
|
199704
|
+
const isPrimaryUser = user.id === primaryUserId;
|
|
199608
199705
|
const userValues = {
|
|
199609
199706
|
...user,
|
|
199610
|
-
timebackId:
|
|
199707
|
+
timebackId: generateTimebackId(user.id, isPrimaryUser)
|
|
199611
199708
|
};
|
|
199612
199709
|
await db.insert(users).values(userValues).onConflictDoNothing();
|
|
199613
199710
|
}
|
|
@@ -199628,7 +199725,7 @@ async function seedDemoData(db) {
|
|
|
199628
199725
|
console.error("❌ Error seeding demo data:", error2);
|
|
199629
199726
|
throw error2;
|
|
199630
199727
|
}
|
|
199631
|
-
return DEMO_USERS.
|
|
199728
|
+
return DEMO_USERS.player;
|
|
199632
199729
|
}
|
|
199633
199730
|
async function checkIfNeedsSeeding(db) {
|
|
199634
199731
|
try {
|
|
@@ -199664,6 +199761,10 @@ async function setupServerDatabase(processedOptions, project) {
|
|
|
199664
199761
|
}
|
|
199665
199762
|
init_src();
|
|
199666
199763
|
var import_json_colorizer = __toESM2(require_dist22(), 1);
|
|
199764
|
+
var customLogger;
|
|
199765
|
+
function setLogger(logger3) {
|
|
199766
|
+
customLogger = logger3;
|
|
199767
|
+
}
|
|
199667
199768
|
function processServerOptions(port, options) {
|
|
199668
199769
|
const {
|
|
199669
199770
|
verbose = false,
|
|
@@ -199712,6 +199813,10 @@ async function startRealtimeServer(realtimeOptions, betterAuthSecret) {
|
|
|
199712
199813
|
if (!realtimeOptions.enabled) {
|
|
199713
199814
|
return null;
|
|
199714
199815
|
}
|
|
199816
|
+
if (!realtimeOptions.port) {
|
|
199817
|
+
return null;
|
|
199818
|
+
}
|
|
199819
|
+
await waitForPort(realtimeOptions.port);
|
|
199715
199820
|
if (typeof Bun === "undefined") {
|
|
199716
199821
|
try {
|
|
199717
199822
|
return Promise.resolve().then(() => (init_sandbox(), exports_sandbox)).then(({ createSandboxRealtimeServer: createSandboxRealtimeServer2 }) => createSandboxRealtimeServer2({
|
|
@@ -204967,12 +205072,32 @@ async function getUserMe(ctx) {
|
|
|
204967
205072
|
log2.error(`[API /users/me] User not found in DB for valid token ID: ${user.id}`);
|
|
204968
205073
|
throw ApiError.notFound("User not found");
|
|
204969
205074
|
}
|
|
205075
|
+
const timeback3 = userData.timebackId ? await fetchUserTimebackData(userData.timebackId, ctx.gameId) : undefined;
|
|
205076
|
+
if (ctx.gameId) {
|
|
205077
|
+
return {
|
|
205078
|
+
id: userData.id,
|
|
205079
|
+
name: userData.name,
|
|
205080
|
+
role: userData.role,
|
|
205081
|
+
username: userData.username,
|
|
205082
|
+
email: userData.email,
|
|
205083
|
+
timeback: timeback3
|
|
205084
|
+
};
|
|
205085
|
+
}
|
|
204970
205086
|
const timebackAccount = await db.query.accounts.findFirst({
|
|
204971
205087
|
where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
|
|
204972
205088
|
});
|
|
204973
|
-
const timeback3 = userData.timebackId ? await fetchUserTimebackData(userData.timebackId) : undefined;
|
|
204974
205089
|
return {
|
|
204975
|
-
|
|
205090
|
+
id: userData.id,
|
|
205091
|
+
name: userData.name,
|
|
205092
|
+
username: userData.username,
|
|
205093
|
+
email: userData.email,
|
|
205094
|
+
emailVerified: userData.emailVerified,
|
|
205095
|
+
image: userData.image,
|
|
205096
|
+
role: userData.role,
|
|
205097
|
+
developerStatus: userData.developerStatus,
|
|
205098
|
+
characterCreated: userData.characterCreated,
|
|
205099
|
+
createdAt: userData.createdAt,
|
|
205100
|
+
updatedAt: userData.updatedAt,
|
|
204976
205101
|
hasTimebackAccount: !!timebackAccount,
|
|
204977
205102
|
timeback: timeback3
|
|
204978
205103
|
};
|
|
@@ -204983,15 +205108,104 @@ async function getUserMe(ctx) {
|
|
|
204983
205108
|
throw ApiError.internal("Internal server error", error2);
|
|
204984
205109
|
}
|
|
204985
205110
|
}
|
|
205111
|
+
init_src();
|
|
205112
|
+
function shouldMockTimeback() {
|
|
205113
|
+
return config.timeback.timebackId === "mock";
|
|
205114
|
+
}
|
|
205115
|
+
function getMockStudentProfile() {
|
|
205116
|
+
const { organization: org, role } = config.timeback;
|
|
205117
|
+
return {
|
|
205118
|
+
role: role ?? "student",
|
|
205119
|
+
organizations: [
|
|
205120
|
+
{
|
|
205121
|
+
id: org?.id ?? "PLAYCADEMY",
|
|
205122
|
+
name: org?.name ?? "Playcademy Studios",
|
|
205123
|
+
type: org?.type ?? "department",
|
|
205124
|
+
isPrimary: true
|
|
205125
|
+
}
|
|
205126
|
+
]
|
|
205127
|
+
};
|
|
205128
|
+
}
|
|
205129
|
+
async function getMockEnrollments(db) {
|
|
205130
|
+
const allIntegrations = await db.query.gameTimebackIntegrations.findMany();
|
|
205131
|
+
return allIntegrations.map((i4) => ({
|
|
205132
|
+
gameId: i4.gameId,
|
|
205133
|
+
grade: i4.grade,
|
|
205134
|
+
subject: i4.subject,
|
|
205135
|
+
courseId: i4.courseId
|
|
205136
|
+
}));
|
|
205137
|
+
}
|
|
205138
|
+
async function getMockTimebackData(db, timebackId, gameId) {
|
|
205139
|
+
const { role, organizations } = getMockStudentProfile();
|
|
205140
|
+
const allEnrollments = await getMockEnrollments(db);
|
|
205141
|
+
const enrollments = gameId ? allEnrollments.filter((e2) => e2.gameId === gameId).map(({ gameId: _5, ...rest }) => rest) : allEnrollments;
|
|
205142
|
+
log2.debug("[Timeback] Sandbox is using mock data", {
|
|
205143
|
+
timebackId,
|
|
205144
|
+
role,
|
|
205145
|
+
enrollments: enrollments.map((e2) => `${e2.subject}:${e2.grade}`),
|
|
205146
|
+
organizations: organizations.map((o5) => `${o5.name ?? o5.id}`)
|
|
205147
|
+
});
|
|
205148
|
+
return { id: timebackId, role, enrollments, organizations };
|
|
205149
|
+
}
|
|
205150
|
+
async function buildMockUserResponse(db, user, gameId) {
|
|
205151
|
+
const timeback3 = user.timebackId ? await getMockTimebackData(db, user.timebackId, gameId) : undefined;
|
|
205152
|
+
if (gameId) {
|
|
205153
|
+
return {
|
|
205154
|
+
id: user.id,
|
|
205155
|
+
name: user.name,
|
|
205156
|
+
role: user.role,
|
|
205157
|
+
username: user.username,
|
|
205158
|
+
email: user.email,
|
|
205159
|
+
timeback: timeback3
|
|
205160
|
+
};
|
|
205161
|
+
}
|
|
205162
|
+
const timebackAccount = await db.query.accounts.findFirst({
|
|
205163
|
+
where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
|
|
205164
|
+
});
|
|
205165
|
+
return {
|
|
205166
|
+
id: user.id,
|
|
205167
|
+
name: user.name,
|
|
205168
|
+
username: user.username,
|
|
205169
|
+
email: user.email,
|
|
205170
|
+
emailVerified: user.emailVerified,
|
|
205171
|
+
image: user.image,
|
|
205172
|
+
role: user.role,
|
|
205173
|
+
developerStatus: user.developerStatus,
|
|
205174
|
+
characterCreated: user.characterCreated,
|
|
205175
|
+
createdAt: user.createdAt,
|
|
205176
|
+
updatedAt: user.updatedAt,
|
|
205177
|
+
hasTimebackAccount: !!timebackAccount,
|
|
205178
|
+
timeback: timeback3
|
|
205179
|
+
};
|
|
205180
|
+
}
|
|
204986
205181
|
var usersRouter = new Hono2;
|
|
204987
205182
|
usersRouter.get("/me", async (c3) => {
|
|
204988
|
-
const
|
|
204989
|
-
|
|
204990
|
-
|
|
204991
|
-
|
|
204992
|
-
|
|
204993
|
-
}
|
|
205183
|
+
const user = c3.get("user");
|
|
205184
|
+
const gameId = c3.get("gameId");
|
|
205185
|
+
if (!user) {
|
|
205186
|
+
const error2 = ApiError.unauthorized("Valid session or bearer token required");
|
|
205187
|
+
return c3.json(createErrorResponse(error2), error2.statusCode);
|
|
205188
|
+
}
|
|
204994
205189
|
try {
|
|
205190
|
+
if (shouldMockTimeback()) {
|
|
205191
|
+
const db = c3.get("db");
|
|
205192
|
+
const userData2 = await db.query.users.findFirst({
|
|
205193
|
+
where: eq(users.id, user.id)
|
|
205194
|
+
});
|
|
205195
|
+
if (!userData2) {
|
|
205196
|
+
const error2 = ApiError.notFound("User not found");
|
|
205197
|
+
return c3.json(createErrorResponse(error2), error2.statusCode);
|
|
205198
|
+
}
|
|
205199
|
+
const response = await buildMockUserResponse(db, userData2, gameId);
|
|
205200
|
+
return c3.json(response);
|
|
205201
|
+
}
|
|
205202
|
+
const ctx = {
|
|
205203
|
+
user,
|
|
205204
|
+
params: {},
|
|
205205
|
+
url: new URL(c3.req.url),
|
|
205206
|
+
request: c3.req.raw,
|
|
205207
|
+
gameId
|
|
205208
|
+
};
|
|
204995
205209
|
const userData = await getUserMe(ctx);
|
|
204996
205210
|
return c3.json(userData);
|
|
204997
205211
|
} catch (error2) {
|
|
@@ -210241,7 +210455,7 @@ async function getTodayTimeBackXp(ctx) {
|
|
|
210241
210455
|
throw error2;
|
|
210242
210456
|
if (error2 instanceof InvalidTimezoneError)
|
|
210243
210457
|
throw ApiError.badRequest(error2.message);
|
|
210244
|
-
log2.error("[
|
|
210458
|
+
log2.error("[Timeback] getTodayTimeBackXp failed", { error: error2 });
|
|
210245
210459
|
throw ApiError.internal("Failed to get today's TimeBack XP", error2);
|
|
210246
210460
|
}
|
|
210247
210461
|
}
|
|
@@ -210257,7 +210471,7 @@ async function getTotalTimeBackXp(ctx) {
|
|
|
210257
210471
|
totalXp: Number(result[0]?.totalXp) || 0
|
|
210258
210472
|
};
|
|
210259
210473
|
} catch (error2) {
|
|
210260
|
-
log2.error("[
|
|
210474
|
+
log2.error("[Timeback] getTotalTimeBackXp failed", { error: error2 });
|
|
210261
210475
|
throw ApiError.internal("Failed to get total TimeBack XP", error2);
|
|
210262
210476
|
}
|
|
210263
210477
|
}
|
|
@@ -210307,7 +210521,7 @@ async function updateTodayTimeBackXp(ctx) {
|
|
|
210307
210521
|
} catch (error2) {
|
|
210308
210522
|
if (error2 instanceof ApiError)
|
|
210309
210523
|
throw error2;
|
|
210310
|
-
log2.error("[
|
|
210524
|
+
log2.error("[Timeback] updateTodayTimeBackXp failed", { error: error2 });
|
|
210311
210525
|
throw ApiError.internal("Failed to update today's TimeBack XP", error2);
|
|
210312
210526
|
}
|
|
210313
210527
|
}
|
|
@@ -210342,7 +210556,7 @@ async function getTimeBackXpHistory(ctx) {
|
|
|
210342
210556
|
}))
|
|
210343
210557
|
};
|
|
210344
210558
|
} catch (error2) {
|
|
210345
|
-
log2.error("[
|
|
210559
|
+
log2.error("[Timeback] getTimeBackXpHistory failed", { error: error2 });
|
|
210346
210560
|
throw ApiError.internal("Failed to get TimeBack XP history", error2);
|
|
210347
210561
|
}
|
|
210348
210562
|
}
|
|
@@ -210357,7 +210571,7 @@ async function getStudentEnrollments(ctx) {
|
|
|
210357
210571
|
throw ApiError.badRequest("Missing timebackId parameter");
|
|
210358
210572
|
}
|
|
210359
210573
|
log2.debug("[API] Getting student enrollments", { userId: user.id, timebackId });
|
|
210360
|
-
const enrollments = await
|
|
210574
|
+
const enrollments = await fetchEnrollmentsFromEduBridge(timebackId);
|
|
210361
210575
|
log2.info("[API] Retrieved student enrollments", {
|
|
210362
210576
|
userId: user.id,
|
|
210363
210577
|
timebackId,
|
|
@@ -210557,13 +210771,23 @@ timebackRouter.post("/end-activity", async (c3) => {
|
|
|
210557
210771
|
});
|
|
210558
210772
|
timebackRouter.get("/enrollments/:timebackId", async (c3) => {
|
|
210559
210773
|
const timebackId = c3.req.param("timebackId");
|
|
210560
|
-
const
|
|
210561
|
-
|
|
210562
|
-
|
|
210563
|
-
|
|
210564
|
-
|
|
210565
|
-
};
|
|
210774
|
+
const user = c3.get("user");
|
|
210775
|
+
if (!user) {
|
|
210776
|
+
const error2 = ApiError.unauthorized("Must be logged in to get enrollments");
|
|
210777
|
+
return c3.json(createErrorResponse(error2), error2.statusCode);
|
|
210778
|
+
}
|
|
210566
210779
|
try {
|
|
210780
|
+
if (shouldMockTimeback()) {
|
|
210781
|
+
const db = c3.get("db");
|
|
210782
|
+
const enrollments2 = await getMockEnrollments(db);
|
|
210783
|
+
return c3.json({ enrollments: enrollments2 });
|
|
210784
|
+
}
|
|
210785
|
+
const ctx = {
|
|
210786
|
+
user,
|
|
210787
|
+
params: { timebackId },
|
|
210788
|
+
url: new URL(c3.req.url),
|
|
210789
|
+
request: c3.req.raw
|
|
210790
|
+
};
|
|
210567
210791
|
const result = await getStudentEnrollments(ctx);
|
|
210568
210792
|
return c3.json(result);
|
|
210569
210793
|
} catch (error2) {
|
|
@@ -210871,6 +211095,7 @@ function registerRoutes(app) {
|
|
|
210871
211095
|
}
|
|
210872
211096
|
var version3 = package_default.version;
|
|
210873
211097
|
async function startServer(port, project, options = {}) {
|
|
211098
|
+
await waitForPort(port);
|
|
210874
211099
|
const processedOptions = processServerOptions(port, options);
|
|
210875
211100
|
const db = await setupServerDatabase(processedOptions, project);
|
|
210876
211101
|
const app = createApp(db, {
|
|
@@ -210883,50 +211108,75 @@ async function startServer(port, project, options = {}) {
|
|
|
210883
211108
|
return {
|
|
210884
211109
|
main: mainServer,
|
|
210885
211110
|
realtime: realtimeServer,
|
|
211111
|
+
timebackMode: getTimebackDisplayMode(),
|
|
211112
|
+
setRole: (role) => {
|
|
211113
|
+
config.timeback.role = role;
|
|
211114
|
+
},
|
|
210886
211115
|
stop: () => {
|
|
210887
|
-
|
|
210888
|
-
|
|
210889
|
-
|
|
210890
|
-
|
|
211116
|
+
return new Promise((resolve2) => {
|
|
211117
|
+
if (realtimeServer?.stop)
|
|
211118
|
+
realtimeServer.stop();
|
|
211119
|
+
if (mainServer.close) {
|
|
211120
|
+
mainServer.close(() => resolve2());
|
|
211121
|
+
} else {
|
|
211122
|
+
resolve2();
|
|
211123
|
+
}
|
|
211124
|
+
});
|
|
210891
211125
|
}
|
|
210892
211126
|
};
|
|
210893
211127
|
}
|
|
210894
211128
|
|
|
210895
211129
|
// src/lib/logging/adapter.ts
|
|
210896
|
-
|
|
210897
|
-
function formatTimestamp2() {
|
|
210898
|
-
const now2 = new Date;
|
|
210899
|
-
const hours = now2.getHours();
|
|
210900
|
-
const minutes = now2.getMinutes().toString().padStart(2, "0");
|
|
210901
|
-
const seconds = now2.getSeconds().toString().padStart(2, "0");
|
|
210902
|
-
const ampm = hours >= 12 ? "PM" : "AM";
|
|
210903
|
-
const displayHours = hours % 12 || 12;
|
|
210904
|
-
return import_picocolors3.dim(`${displayHours}:${minutes}:${seconds} ${ampm}`);
|
|
210905
|
-
}
|
|
210906
|
-
function createLoggerAdapter(prefix2) {
|
|
210907
|
-
const formattedPrefix = import_picocolors3.dim(`(${prefix2})`);
|
|
210908
|
-
const label = import_picocolors3.cyan(import_picocolors3.bold("[playcademy]"));
|
|
211130
|
+
function createLoggerAdapter(domain) {
|
|
210909
211131
|
return {
|
|
210910
|
-
info: (msg) => console.log(`${
|
|
210911
|
-
warn: (msg) => console.warn(`${
|
|
210912
|
-
error: (msg) => console.error(`${
|
|
211132
|
+
info: (msg) => console.log(`${createLogPrefix("playcademy", domain)} ${msg}`),
|
|
211133
|
+
warn: (msg) => console.warn(`${createLogPrefix("playcademy", domain)} ${msg}`),
|
|
211134
|
+
error: (msg) => console.error(`${createLogPrefix("playcademy", domain)} ${msg}`)
|
|
210913
211135
|
};
|
|
210914
211136
|
}
|
|
210915
211137
|
// src/lib/logging/utils.ts
|
|
210916
|
-
var
|
|
210917
|
-
|
|
211138
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
211139
|
+
|
|
211140
|
+
// ../utils/src/string.ts
|
|
211141
|
+
function pluralize(count2, singular, plural) {
|
|
211142
|
+
return count2 === 1 ? singular : plural || `${singular}s`;
|
|
211143
|
+
}
|
|
211144
|
+
|
|
211145
|
+
// src/lib/logging/utils.ts
|
|
211146
|
+
function createBackendBannerOptions(backendPort, vitePort) {
|
|
211147
|
+
if (!backendPort)
|
|
211148
|
+
return;
|
|
211149
|
+
return { port: backendPort, vitePort };
|
|
211150
|
+
}
|
|
211151
|
+
function createTimebackBannerOptions(timebackMode, courseCount) {
|
|
211152
|
+
if (!timebackMode || !courseCount)
|
|
211153
|
+
return;
|
|
211154
|
+
return { courseCount, mode: timebackMode };
|
|
211155
|
+
}
|
|
211156
|
+
function printBanner(viteConfig, options) {
|
|
210918
211157
|
const INDENT = " ".repeat(2);
|
|
211158
|
+
const { version: version4, gameName, sandbox, backend, realtimePort, timeback } = options;
|
|
210919
211159
|
viteConfig.logger.info("");
|
|
210920
|
-
viteConfig.logger.info(`${INDENT}${
|
|
211160
|
+
viteConfig.logger.info(`${INDENT}${import_picocolors3.green(import_picocolors3.bold("PLAYCADEMY"))} ${import_picocolors3.green(`v${version4}`)}`);
|
|
210921
211161
|
viteConfig.logger.info("");
|
|
210922
|
-
|
|
210923
|
-
|
|
210924
|
-
|
|
210925
|
-
|
|
210926
|
-
viteConfig.logger.info(`${INDENT}${
|
|
211162
|
+
if (gameName) {
|
|
211163
|
+
viteConfig.logger.info(`${INDENT}${import_picocolors3.green("➜")} ${import_picocolors3.bold("Game:")} ${import_picocolors3.cyan(gameName)}`);
|
|
211164
|
+
}
|
|
211165
|
+
if (sandbox?.enabled) {
|
|
211166
|
+
viteConfig.logger.info(`${INDENT}${import_picocolors3.green("➜")} ${import_picocolors3.bold("Sandbox:")} ${import_picocolors3.cyan(`http://localhost:${import_picocolors3.bold(sandbox.port.toString())}/api`)}`);
|
|
211167
|
+
} else if (sandbox) {
|
|
211168
|
+
viteConfig.logger.info(`${INDENT}${import_picocolors3.green("➜")} ${import_picocolors3.bold("Sandbox:")} ${import_picocolors3.cyan("Disabled")}`);
|
|
211169
|
+
}
|
|
211170
|
+
if (backend) {
|
|
211171
|
+
const backendUrl = backend.vitePort ? `http://localhost:${import_picocolors3.bold(backend.vitePort.toString())}/api ${import_picocolors3.dim(`(via ${backend.port})`)}` : `http://localhost:${import_picocolors3.bold(backend.port.toString())}/api`;
|
|
211172
|
+
viteConfig.logger.info(`${INDENT}${import_picocolors3.green("➜")} ${import_picocolors3.bold("Backend:")} ${import_picocolors3.cyan(backendUrl)}`);
|
|
211173
|
+
}
|
|
211174
|
+
if (realtimePort) {
|
|
211175
|
+
viteConfig.logger.info(`${INDENT}${import_picocolors3.green("➜")} ${import_picocolors3.bold("Realtime:")} ${import_picocolors3.cyan(`ws://localhost:${import_picocolors3.bold(realtimePort.toString())}`)}`);
|
|
210927
211176
|
}
|
|
210928
|
-
if (
|
|
210929
|
-
|
|
211177
|
+
if (timeback && timeback.courseCount > 0) {
|
|
211178
|
+
const label = `${timeback.courseCount} ${pluralize(timeback.courseCount, "course")} ${import_picocolors3.dim(`(${timeback.mode})`)}`;
|
|
211179
|
+
viteConfig.logger.info(`${INDENT}${import_picocolors3.green("➜")} ${import_picocolors3.bold("Timeback:")} ${import_picocolors3.cyan(label)}`);
|
|
210930
211180
|
}
|
|
210931
211181
|
viteConfig.logger.info("");
|
|
210932
211182
|
}
|
|
@@ -210985,14 +211235,35 @@ async function extractProjectInfo(viteConfig, timebackOptions) {
|
|
|
210985
211235
|
}
|
|
210986
211236
|
|
|
210987
211237
|
// src/lib/sandbox/timeback.ts
|
|
210988
|
-
var
|
|
210989
|
-
|
|
210990
|
-
|
|
210991
|
-
|
|
210992
|
-
|
|
210993
|
-
|
|
210994
|
-
|
|
210995
|
-
|
|
211238
|
+
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
211239
|
+
// ../constants/src/overworld.ts
|
|
211240
|
+
var ITEM_SLUGS4 = {
|
|
211241
|
+
PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
|
|
211242
|
+
PLAYCADEMY_XP: "PLAYCADEMY_XP",
|
|
211243
|
+
FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
|
|
211244
|
+
EARLY_ADOPTER_BADGE: "EARLY_ADOPTER_BADGE",
|
|
211245
|
+
FIRST_GAME_BADGE: "FIRST_GAME_BADGE",
|
|
211246
|
+
COMMON_SWORD: "COMMON_SWORD",
|
|
211247
|
+
SMALL_HEALTH_POTION: "SMALL_HEALTH_POTION",
|
|
211248
|
+
SMALL_BACKPACK: "SMALL_BACKPACK",
|
|
211249
|
+
LAVA_LAMP: "LAVA_LAMP",
|
|
211250
|
+
BOOMBOX: "BOOMBOX",
|
|
211251
|
+
CABIN_BED: "CABIN_BED"
|
|
211252
|
+
};
|
|
211253
|
+
var CURRENCIES4 = {
|
|
211254
|
+
PRIMARY: ITEM_SLUGS4.PLAYCADEMY_CREDITS,
|
|
211255
|
+
XP: ITEM_SLUGS4.PLAYCADEMY_XP
|
|
211256
|
+
};
|
|
211257
|
+
var BADGES4 = {
|
|
211258
|
+
FOUNDING_MEMBER: ITEM_SLUGS4.FOUNDING_MEMBER_BADGE,
|
|
211259
|
+
EARLY_ADOPTER: ITEM_SLUGS4.EARLY_ADOPTER_BADGE,
|
|
211260
|
+
FIRST_GAME: ITEM_SLUGS4.FIRST_GAME_BADGE
|
|
211261
|
+
};
|
|
211262
|
+
// ../constants/src/timeback.ts
|
|
211263
|
+
var TIMEBACK_ORG_SOURCED_ID3 = "PLAYCADEMY";
|
|
211264
|
+
var TIMEBACK_ORG_NAME3 = "Playcademy Studios";
|
|
211265
|
+
var TIMEBACK_ORG_TYPE3 = "department";
|
|
211266
|
+
// src/lib/sandbox/timeback.ts
|
|
210996
211267
|
function detectTimebackOptions() {
|
|
210997
211268
|
if (process.env.TIMEBACK_LOCAL === "true") {
|
|
210998
211269
|
return {
|
|
@@ -211000,7 +211271,7 @@ function detectTimebackOptions() {
|
|
|
211000
211271
|
onerosterApiUrl: process.env.TIMEBACK_ONEROSTER_API_URL,
|
|
211001
211272
|
caliperApiUrl: process.env.TIMEBACK_CALIPER_API_URL,
|
|
211002
211273
|
courseId: process.env.SANDBOX_TIMEBACK_COURSE_ID,
|
|
211003
|
-
|
|
211274
|
+
timebackId: process.env.SANDBOX_TIMEBACK_STUDENT_ID
|
|
211004
211275
|
};
|
|
211005
211276
|
}
|
|
211006
211277
|
if (process.env.TIMEBACK_API_CLIENT_ID) {
|
|
@@ -211012,7 +211283,7 @@ function detectTimebackOptions() {
|
|
|
211012
211283
|
clientSecret: process.env.TIMEBACK_API_CLIENT_SECRET,
|
|
211013
211284
|
authUrl: process.env.TIMEBACK_API_AUTH_URL,
|
|
211014
211285
|
courseId: process.env.SANDBOX_TIMEBACK_COURSE_ID,
|
|
211015
|
-
|
|
211286
|
+
timebackId: process.env.SANDBOX_TIMEBACK_STUDENT_ID
|
|
211016
211287
|
};
|
|
211017
211288
|
}
|
|
211018
211289
|
return;
|
|
@@ -211026,59 +211297,77 @@ function hasTimebackCredentials2() {
|
|
|
211026
211297
|
}
|
|
211027
211298
|
return !!(config2.onerosterApiUrl && config2.clientId && config2.clientSecret && config2.authUrl);
|
|
211028
211299
|
}
|
|
211029
|
-
function validateTimebackConfig(viteConfig,
|
|
211030
|
-
if (!
|
|
211300
|
+
function validateTimebackConfig(viteConfig, timeback2) {
|
|
211301
|
+
if (!timeback2?.courses)
|
|
211031
211302
|
return;
|
|
211032
|
-
const realCourses = Object.entries(
|
|
211303
|
+
const realCourses = Object.entries(timeback2.courses).filter(([, value]) => value !== "mock");
|
|
211033
211304
|
if (realCourses.length > 0 && !hasTimebackCredentials2()) {
|
|
211034
211305
|
const courseList = realCourses.map(([key]) => key).join(", ");
|
|
211035
211306
|
viteConfig.logger.warn("");
|
|
211036
|
-
viteConfig.logger.warn(
|
|
211037
|
-
viteConfig.logger.warn(
|
|
211038
|
-
viteConfig.logger.warn(
|
|
211307
|
+
viteConfig.logger.warn(import_picocolors4.default.yellow(`⚠️ TimeBack: Real course IDs for ${import_picocolors4.default.bold(courseList)} but credentials missing.`));
|
|
211308
|
+
viteConfig.logger.warn(import_picocolors4.default.dim(` Required: TIMEBACK_API_CLIENT_ID, TIMEBACK_API_CLIENT_SECRET, TIMEBACK_API_AUTH_URL, TIMEBACK_ONEROSTER_API_URL`));
|
|
211309
|
+
viteConfig.logger.warn(import_picocolors4.default.dim(` Or use 'mock' for local testing.`));
|
|
211039
211310
|
viteConfig.logger.warn("");
|
|
211040
211311
|
}
|
|
211041
211312
|
}
|
|
211042
|
-
function
|
|
211043
|
-
if (!
|
|
211044
|
-
return
|
|
211313
|
+
function resolveOrganization(orgConfig) {
|
|
211314
|
+
if (!orgConfig || orgConfig === "mock") {
|
|
211315
|
+
return {
|
|
211316
|
+
id: TIMEBACK_ORG_SOURCED_ID3,
|
|
211317
|
+
name: TIMEBACK_ORG_NAME3,
|
|
211318
|
+
type: TIMEBACK_ORG_TYPE3
|
|
211319
|
+
};
|
|
211045
211320
|
}
|
|
211321
|
+
return {
|
|
211322
|
+
id: orgConfig.id ?? TIMEBACK_ORG_SOURCED_ID3,
|
|
211323
|
+
name: orgConfig.name ?? TIMEBACK_ORG_NAME3,
|
|
211324
|
+
type: orgConfig.type ?? TIMEBACK_ORG_TYPE3
|
|
211325
|
+
};
|
|
211326
|
+
}
|
|
211327
|
+
function resolveOrganizations(orgConfig) {
|
|
211328
|
+
const org = resolveOrganization(orgConfig);
|
|
211329
|
+
return [
|
|
211330
|
+
{
|
|
211331
|
+
id: org.id,
|
|
211332
|
+
name: org.name ?? null,
|
|
211333
|
+
type: org.type ?? TIMEBACK_ORG_TYPE3,
|
|
211334
|
+
isPrimary: true
|
|
211335
|
+
}
|
|
211336
|
+
];
|
|
211337
|
+
}
|
|
211338
|
+
function generateTimebackJson(context) {
|
|
211339
|
+
if (!context?.baseCourses || context.baseCourses.length === 0) {
|
|
211340
|
+
return "null";
|
|
211341
|
+
}
|
|
211342
|
+
const { baseCourses, overrides } = context;
|
|
211046
211343
|
const enrollments = [];
|
|
211047
|
-
for (const
|
|
211048
|
-
const
|
|
211049
|
-
const
|
|
211050
|
-
|
|
211051
|
-
const grade = gradeStr ? parseInt(gradeStr, 10) : NaN;
|
|
211052
|
-
if (!subject || isNaN(grade))
|
|
211344
|
+
for (const course of baseCourses) {
|
|
211345
|
+
const key = `${course.subject}:${course.grade}`;
|
|
211346
|
+
const override = overrides?.courses?.[key];
|
|
211347
|
+
if (override === null)
|
|
211053
211348
|
continue;
|
|
211054
|
-
const courseId =
|
|
211055
|
-
enrollments.push({
|
|
211349
|
+
const courseId = override && override !== "mock" ? override : `mock-${course.subject.toLowerCase()}-g${course.grade}`;
|
|
211350
|
+
enrollments.push({
|
|
211351
|
+
subject: course.subject,
|
|
211352
|
+
grade: course.grade,
|
|
211353
|
+
courseId
|
|
211354
|
+
});
|
|
211056
211355
|
}
|
|
211057
211356
|
if (enrollments.length === 0) {
|
|
211058
|
-
return;
|
|
211357
|
+
return "null";
|
|
211059
211358
|
}
|
|
211060
211359
|
const roleOverride = getTimebackRoleOverride();
|
|
211061
|
-
const role = roleOverride ??
|
|
211062
|
-
|
|
211360
|
+
const role = roleOverride ?? overrides?.role ?? "student";
|
|
211361
|
+
const organizations = resolveOrganizations(overrides?.organization);
|
|
211362
|
+
return JSON.stringify({ role, enrollments, organizations });
|
|
211063
211363
|
}
|
|
211064
211364
|
|
|
211065
211365
|
// src/lib/sandbox/server.ts
|
|
211066
|
-
function printSandboxInfo(viteConfig, apiPort, realtimePort, projectInfo, realtimeEnabled) {
|
|
211067
|
-
viteConfig.logger.info("");
|
|
211068
|
-
viteConfig.logger.info(` ${import_picocolors6.default.green(import_picocolors6.default.bold("PLAYCADEMY"))} ${import_picocolors6.default.green(`v${version3}`)}`);
|
|
211069
|
-
viteConfig.logger.info("");
|
|
211070
|
-
viteConfig.logger.info(` ${import_picocolors6.default.green("➜")} ${import_picocolors6.default.bold("Game:")} ${import_picocolors6.default.cyan(projectInfo.slug)}`);
|
|
211071
|
-
viteConfig.logger.info(` ${import_picocolors6.default.green("➜")} ${import_picocolors6.default.bold("Sandbox:")} ${import_picocolors6.default.cyan(`http://localhost:${import_picocolors6.default.bold(apiPort.toString())}/api`)}`);
|
|
211072
|
-
if (realtimeEnabled) {
|
|
211073
|
-
viteConfig.logger.info(` ${import_picocolors6.default.green("➜")} ${import_picocolors6.default.bold("Realtime:")} ${import_picocolors6.default.cyan(`ws://localhost:${import_picocolors6.default.bold(realtimePort.toString())}`)}`);
|
|
211074
|
-
}
|
|
211075
|
-
viteConfig.logger.info("");
|
|
211076
|
-
}
|
|
211077
211366
|
async function startSandbox(viteConfig, autoStart = true, options = {}) {
|
|
211078
211367
|
const {
|
|
211368
|
+
port = DEFAULT_PORTS2.SANDBOX,
|
|
211079
211369
|
verbose = false,
|
|
211080
211370
|
customUrl,
|
|
211081
|
-
quiet = false,
|
|
211082
211371
|
recreateDb = false,
|
|
211083
211372
|
seed = true,
|
|
211084
211373
|
memoryOnly = false,
|
|
@@ -211086,17 +211375,17 @@ async function startSandbox(viteConfig, autoStart = true, options = {}) {
|
|
|
211086
211375
|
realtimeEnabled = false,
|
|
211087
211376
|
realtimePort,
|
|
211088
211377
|
logLevel = "info",
|
|
211089
|
-
timebackId,
|
|
211090
211378
|
timebackOptions
|
|
211091
211379
|
} = options;
|
|
211380
|
+
const timebackDisabled = timebackOptions === false;
|
|
211092
211381
|
if (!autoStart || viteConfig.command !== "serve") {
|
|
211093
211382
|
const baseUrl = customUrl ?? `http://localhost:${DEFAULT_PORTS2.SANDBOX}`;
|
|
211094
211383
|
const deriveRealtimeUrl = (url) => {
|
|
211095
211384
|
try {
|
|
211096
211385
|
const u4 = new URL(url);
|
|
211097
|
-
const
|
|
211386
|
+
const port2 = Number(u4.port || (u4.protocol === "https:" ? 443 : 80));
|
|
211098
211387
|
const wsProto = u4.protocol === "https:" ? "wss:" : "ws:";
|
|
211099
|
-
return `${wsProto}//${u4.hostname}:${
|
|
211388
|
+
return `${wsProto}//${u4.hostname}:${port2 + 1}`;
|
|
211100
211389
|
} catch {
|
|
211101
211390
|
return "ws://localhost:4322";
|
|
211102
211391
|
}
|
|
@@ -211111,21 +211400,24 @@ async function startSandbox(viteConfig, autoStart = true, options = {}) {
|
|
|
211111
211400
|
};
|
|
211112
211401
|
}
|
|
211113
211402
|
try {
|
|
211114
|
-
const
|
|
211115
|
-
const
|
|
211116
|
-
const projectInfo = await extractProjectInfo(viteConfig,
|
|
211403
|
+
const baseUrl = `http://localhost:${port}`;
|
|
211404
|
+
const effectiveTimebackOptions = timebackDisabled ? undefined : timebackOptions || undefined;
|
|
211405
|
+
const projectInfo = await extractProjectInfo(viteConfig, effectiveTimebackOptions);
|
|
211117
211406
|
let sandboxTimebackOptions = detectTimebackOptions();
|
|
211118
|
-
|
|
211407
|
+
const effectiveTimebackId = timebackDisabled ? undefined : effectiveTimebackOptions?.id ?? sandboxTimebackOptions?.timebackId ?? (projectInfo.timebackCourses?.length ? "mock" : undefined);
|
|
211408
|
+
if (effectiveTimebackId) {
|
|
211119
211409
|
sandboxTimebackOptions = {
|
|
211120
211410
|
...sandboxTimebackOptions,
|
|
211121
|
-
|
|
211411
|
+
timebackId: effectiveTimebackId,
|
|
211412
|
+
organization: resolveOrganization(effectiveTimebackOptions?.organization),
|
|
211413
|
+
role: effectiveTimebackOptions?.role
|
|
211122
211414
|
};
|
|
211123
211415
|
}
|
|
211124
|
-
const finalRealtimePort = realtimePort ??
|
|
211416
|
+
const finalRealtimePort = realtimePort ?? port + 1;
|
|
211125
211417
|
const realtimeUrl = `ws://localhost:${finalRealtimePort}`;
|
|
211126
|
-
const server = await startServer(
|
|
211418
|
+
const server = await startServer(port, projectInfo, {
|
|
211127
211419
|
verbose,
|
|
211128
|
-
quiet,
|
|
211420
|
+
quiet: true,
|
|
211129
211421
|
seed,
|
|
211130
211422
|
memoryOnly,
|
|
211131
211423
|
databasePath,
|
|
@@ -211135,33 +211427,22 @@ async function startSandbox(viteConfig, autoStart = true, options = {}) {
|
|
|
211135
211427
|
timeback: sandboxTimebackOptions,
|
|
211136
211428
|
logger: createLoggerAdapter("sandbox")
|
|
211137
211429
|
});
|
|
211138
|
-
writeServerInfo("sandbox", {
|
|
211139
|
-
pid: process.pid,
|
|
211140
|
-
port: sandboxPort,
|
|
211141
|
-
url: baseUrl,
|
|
211142
|
-
startedAt: Date.now(),
|
|
211143
|
-
projectRoot: viteConfig.root
|
|
211144
|
-
});
|
|
211145
|
-
if (!quiet) {
|
|
211146
|
-
setTimeout(() => {
|
|
211147
|
-
printSandboxInfo(viteConfig, sandboxPort, finalRealtimePort, projectInfo, realtimeEnabled);
|
|
211148
|
-
}, 100);
|
|
211149
|
-
}
|
|
211150
211430
|
return {
|
|
211151
211431
|
baseUrl,
|
|
211152
211432
|
realtimeUrl,
|
|
211153
|
-
port
|
|
211433
|
+
port,
|
|
211154
211434
|
realtimePort: realtimeEnabled ? finalRealtimePort : undefined,
|
|
211155
211435
|
project: projectInfo,
|
|
211156
|
-
|
|
211157
|
-
|
|
211436
|
+
timebackMode: server.timebackMode,
|
|
211437
|
+
setRole: server.setRole,
|
|
211438
|
+
cleanup: async () => {
|
|
211158
211439
|
if (server && typeof server.stop === "function") {
|
|
211159
|
-
server.stop();
|
|
211440
|
+
await server.stop();
|
|
211160
211441
|
}
|
|
211161
211442
|
}
|
|
211162
211443
|
};
|
|
211163
211444
|
} catch (error2) {
|
|
211164
|
-
viteConfig.logger.error(
|
|
211445
|
+
viteConfig.logger.error(import_picocolors5.default.red(`[Playcademy] Failed to start sandbox: ${error2}`));
|
|
211165
211446
|
return {
|
|
211166
211447
|
baseUrl: `http://localhost:${DEFAULT_PORTS2.SANDBOX}`,
|
|
211167
211448
|
realtimeUrl: "ws://localhost:4322",
|
|
@@ -211172,216 +211453,212 @@ async function startSandbox(viteConfig, autoStart = true, options = {}) {
|
|
|
211172
211453
|
};
|
|
211173
211454
|
}
|
|
211174
211455
|
}
|
|
211175
|
-
//
|
|
211176
|
-
var
|
|
211177
|
-
|
|
211178
|
-
|
|
211179
|
-
|
|
211180
|
-
|
|
211181
|
-
|
|
211182
|
-
|
|
211183
|
-
|
|
211184
|
-
|
|
211185
|
-
|
|
211186
|
-
|
|
211187
|
-
|
|
211188
|
-
|
|
211189
|
-
|
|
211190
|
-
|
|
211191
|
-
|
|
211192
|
-
|
|
211193
|
-
|
|
211194
|
-
|
|
211195
|
-
|
|
211196
|
-
|
|
211197
|
-
|
|
211198
|
-
|
|
211199
|
-
|
|
211200
|
-
|
|
211201
|
-
|
|
211202
|
-
|
|
211203
|
-
|
|
211204
|
-
|
|
211205
|
-
|
|
211206
|
-
|
|
211207
|
-
|
|
211208
|
-
|
|
211209
|
-
|
|
211210
|
-
|
|
211211
|
-
|
|
211212
|
-
|
|
211213
|
-
|
|
211214
|
-
|
|
211215
|
-
|
|
211216
|
-
|
|
211217
|
-
|
|
211218
|
-
|
|
211219
|
-
|
|
211220
|
-
|
|
211221
|
-
|
|
211222
|
-
|
|
211223
|
-
|
|
211224
|
-
|
|
211225
|
-
|
|
211226
|
-
|
|
211227
|
-
|
|
211228
|
-
|
|
211229
|
-
|
|
211230
|
-
|
|
211231
|
-
|
|
211232
|
-
|
|
211233
|
-
|
|
211234
|
-
|
|
211235
|
-
|
|
211236
|
-
|
|
211237
|
-
|
|
211238
|
-
|
|
211239
|
-
|
|
211240
|
-
|
|
211241
|
-
|
|
211242
|
-
|
|
211243
|
-
|
|
211244
|
-
|
|
211245
|
-
|
|
211246
|
-
|
|
211247
|
-
|
|
211248
|
-
|
|
211249
|
-
|
|
211250
|
-
|
|
211251
|
-
|
|
211252
|
-
|
|
211253
|
-
|
|
211254
|
-
|
|
211255
|
-
|
|
211256
|
-
|
|
211257
|
-
|
|
211258
|
-
|
|
211259
|
-
|
|
211260
|
-
|
|
211261
|
-
|
|
211262
|
-
|
|
211263
|
-
|
|
211264
|
-
|
|
211265
|
-
|
|
211266
|
-
|
|
211267
|
-
|
|
211268
|
-
|
|
211269
|
-
|
|
211270
|
-
|
|
211271
|
-
|
|
211272
|
-
|
|
211273
|
-
|
|
211274
|
-
|
|
211275
|
-
|
|
211276
|
-
|
|
211277
|
-
|
|
211278
|
-
|
|
211279
|
-
|
|
211280
|
-
|
|
211281
|
-
|
|
211282
|
-
|
|
211283
|
-
|
|
211284
|
-
|
|
211285
|
-
|
|
211286
|
-
|
|
211287
|
-
|
|
211288
|
-
|
|
211289
|
-
|
|
211290
|
-
|
|
211291
|
-
|
|
211292
|
-
|
|
211293
|
-
|
|
211294
|
-
|
|
211295
|
-
|
|
211296
|
-
|
|
211297
|
-
|
|
211298
|
-
|
|
211299
|
-
|
|
211300
|
-
|
|
211301
|
-
|
|
211302
|
-
|
|
211303
|
-
|
|
211304
|
-
|
|
211305
|
-
|
|
211306
|
-
|
|
211307
|
-
|
|
211308
|
-
|
|
211309
|
-
|
|
211310
|
-
|
|
211311
|
-
|
|
211312
|
-
|
|
211313
|
-
|
|
211314
|
-
|
|
211315
|
-
|
|
211316
|
-
|
|
211317
|
-
|
|
211318
|
-
|
|
211319
|
-
|
|
211320
|
-
|
|
211321
|
-
|
|
211322
|
-
|
|
211323
|
-
|
|
211324
|
-
|
|
211325
|
-
|
|
211326
|
-
|
|
211327
|
-
|
|
211328
|
-
|
|
211329
|
-
|
|
211330
|
-
|
|
211331
|
-
|
|
211332
|
-
|
|
211333
|
-
|
|
211334
|
-
|
|
211335
|
-
|
|
211336
|
-
|
|
211337
|
-
|
|
211338
|
-
|
|
211339
|
-
|
|
211340
|
-
|
|
211341
|
-
|
|
211342
|
-
|
|
211343
|
-
|
|
211344
|
-
|
|
211345
|
-
|
|
211346
|
-
|
|
211347
|
-
|
|
211348
|
-
|
|
211349
|
-
|
|
211350
|
-
|
|
211351
|
-
|
|
211352
|
-
|
|
211353
|
-
|
|
211354
|
-
|
|
211355
|
-
|
|
211356
|
-
|
|
211357
|
-
|
|
211358
|
-
|
|
211359
|
-
|
|
211360
|
-
|
|
211361
|
-
if (event.source === gameFrame.contentWindow) {
|
|
211362
|
-
const { type, ...payload } = event.data || {}
|
|
211363
|
-
if (type && type.startsWith('PLAYCADEMY_')) {
|
|
211364
|
-
logIfDebug(
|
|
211365
|
-
'[PlaycademyDevShell] Received message from game:',
|
|
211366
|
-
type,
|
|
211367
|
-
payload,
|
|
211368
|
-
)
|
|
211369
|
-
// Bridge the message to the local context using CustomEvent
|
|
211370
|
-
messaging.send(type, payload)
|
|
211371
|
-
}
|
|
211372
|
-
}
|
|
211373
|
-
})
|
|
211456
|
+
// ../sandbox/dist/constants.js
|
|
211457
|
+
var now2 = new Date;
|
|
211458
|
+
var DEMO_USER_IDS2 = {
|
|
211459
|
+
player: "00000000-0000-0000-0000-000000000001",
|
|
211460
|
+
developer: "00000000-0000-0000-0000-000000000002",
|
|
211461
|
+
admin: "00000000-0000-0000-0000-000000000003",
|
|
211462
|
+
pendingDeveloper: "00000000-0000-0000-0000-000000000004",
|
|
211463
|
+
unverifiedPlayer: "00000000-0000-0000-0000-000000000005"
|
|
211464
|
+
};
|
|
211465
|
+
var DEMO_USERS2 = {
|
|
211466
|
+
admin: {
|
|
211467
|
+
id: DEMO_USER_IDS2.admin,
|
|
211468
|
+
name: "Admin User",
|
|
211469
|
+
username: "admin_user",
|
|
211470
|
+
email: "admin@playcademy.com",
|
|
211471
|
+
emailVerified: true,
|
|
211472
|
+
image: null,
|
|
211473
|
+
role: "admin",
|
|
211474
|
+
developerStatus: "approved",
|
|
211475
|
+
createdAt: now2,
|
|
211476
|
+
updatedAt: now2
|
|
211477
|
+
},
|
|
211478
|
+
player: {
|
|
211479
|
+
id: DEMO_USER_IDS2.player,
|
|
211480
|
+
name: "Player User",
|
|
211481
|
+
username: "player_user",
|
|
211482
|
+
email: "player@playcademy.com",
|
|
211483
|
+
emailVerified: true,
|
|
211484
|
+
image: null,
|
|
211485
|
+
role: "player",
|
|
211486
|
+
developerStatus: "none",
|
|
211487
|
+
createdAt: now2,
|
|
211488
|
+
updatedAt: now2
|
|
211489
|
+
},
|
|
211490
|
+
developer: {
|
|
211491
|
+
id: DEMO_USER_IDS2.developer,
|
|
211492
|
+
name: "Developer User",
|
|
211493
|
+
username: "developer_user",
|
|
211494
|
+
email: "developer@playcademy.com",
|
|
211495
|
+
emailVerified: true,
|
|
211496
|
+
image: null,
|
|
211497
|
+
role: "developer",
|
|
211498
|
+
developerStatus: "approved",
|
|
211499
|
+
createdAt: now2,
|
|
211500
|
+
updatedAt: now2
|
|
211501
|
+
},
|
|
211502
|
+
pendingDeveloper: {
|
|
211503
|
+
id: DEMO_USER_IDS2.pendingDeveloper,
|
|
211504
|
+
name: "Pending Developer",
|
|
211505
|
+
username: "pending_dev",
|
|
211506
|
+
email: "pending@playcademy.com",
|
|
211507
|
+
emailVerified: true,
|
|
211508
|
+
image: null,
|
|
211509
|
+
role: "developer",
|
|
211510
|
+
developerStatus: "pending",
|
|
211511
|
+
createdAt: now2,
|
|
211512
|
+
updatedAt: now2
|
|
211513
|
+
},
|
|
211514
|
+
unverifiedPlayer: {
|
|
211515
|
+
id: DEMO_USER_IDS2.unverifiedPlayer,
|
|
211516
|
+
name: "Unverified Player",
|
|
211517
|
+
username: "unverified_player",
|
|
211518
|
+
email: "unverified@playcademy.com",
|
|
211519
|
+
emailVerified: false,
|
|
211520
|
+
image: null,
|
|
211521
|
+
role: "player",
|
|
211522
|
+
developerStatus: "none",
|
|
211523
|
+
createdAt: now2,
|
|
211524
|
+
updatedAt: now2
|
|
211525
|
+
}
|
|
211526
|
+
};
|
|
211527
|
+
var DEMO_USER2 = DEMO_USERS2.player;
|
|
211528
|
+
var DEMO_TOKENS2 = {
|
|
211529
|
+
"sandbox-demo-token": DEMO_USERS2.player,
|
|
211530
|
+
"sandbox-admin-token": DEMO_USERS2.admin,
|
|
211531
|
+
"sandbox-player-token": DEMO_USERS2.player,
|
|
211532
|
+
"sandbox-developer-token": DEMO_USERS2.developer,
|
|
211533
|
+
"sandbox-pending-dev-token": DEMO_USERS2.pendingDeveloper,
|
|
211534
|
+
"sandbox-unverified-token": DEMO_USERS2.unverifiedPlayer,
|
|
211535
|
+
"mock-game-token-for-local-dev": DEMO_USERS2.player
|
|
211536
|
+
};
|
|
211537
|
+
var DEMO_ITEM_IDS2 = {
|
|
211538
|
+
playcademyCredits: "10000000-0000-0000-0000-000000000001",
|
|
211539
|
+
foundingMemberBadge: "10000000-0000-0000-0000-000000000002",
|
|
211540
|
+
earlyAdopterBadge: "10000000-0000-0000-0000-000000000003",
|
|
211541
|
+
firstGameBadge: "10000000-0000-0000-0000-000000000004",
|
|
211542
|
+
commonSword: "10000000-0000-0000-0000-000000000005",
|
|
211543
|
+
smallHealthPotion: "10000000-0000-0000-0000-000000000006",
|
|
211544
|
+
smallBackpack: "10000000-0000-0000-0000-000000000007"
|
|
211545
|
+
};
|
|
211546
|
+
var PLAYCADEMY_CREDITS_ID2 = DEMO_ITEM_IDS2.playcademyCredits;
|
|
211547
|
+
var SAMPLE_ITEMS2 = [
|
|
211548
|
+
{
|
|
211549
|
+
id: PLAYCADEMY_CREDITS_ID2,
|
|
211550
|
+
slug: "PLAYCADEMY_CREDITS",
|
|
211551
|
+
gameId: null,
|
|
211552
|
+
displayName: "PLAYCADEMY credits",
|
|
211553
|
+
description: "The main currency used across PLAYCADEMY.",
|
|
211554
|
+
type: "currency",
|
|
211555
|
+
isPlaceable: false,
|
|
211556
|
+
imageUrl: "http://playcademy-sandbox.local/playcademy-credit.png",
|
|
211557
|
+
metadata: {
|
|
211558
|
+
rarity: "common"
|
|
211559
|
+
}
|
|
211560
|
+
},
|
|
211561
|
+
{
|
|
211562
|
+
id: DEMO_ITEM_IDS2.foundingMemberBadge,
|
|
211563
|
+
slug: "FOUNDING_MEMBER_BADGE",
|
|
211564
|
+
gameId: null,
|
|
211565
|
+
displayName: "Founding Member Badge",
|
|
211566
|
+
description: "Reserved for founding core team of the PLAYCADEMY platform.",
|
|
211567
|
+
type: "badge",
|
|
211568
|
+
isPlaceable: false,
|
|
211569
|
+
imageUrl: null,
|
|
211570
|
+
metadata: {
|
|
211571
|
+
rarity: "legendary"
|
|
211572
|
+
}
|
|
211573
|
+
},
|
|
211574
|
+
{
|
|
211575
|
+
id: DEMO_ITEM_IDS2.earlyAdopterBadge,
|
|
211576
|
+
slug: "EARLY_ADOPTER_BADGE",
|
|
211577
|
+
gameId: null,
|
|
211578
|
+
displayName: "Early Adopter Badge",
|
|
211579
|
+
description: "Awarded to users who joined during the beta phase.",
|
|
211580
|
+
type: "badge",
|
|
211581
|
+
isPlaceable: false,
|
|
211582
|
+
imageUrl: null,
|
|
211583
|
+
metadata: {
|
|
211584
|
+
rarity: "epic"
|
|
211585
|
+
}
|
|
211586
|
+
},
|
|
211587
|
+
{
|
|
211588
|
+
id: DEMO_ITEM_IDS2.firstGameBadge,
|
|
211589
|
+
slug: "FIRST_GAME_BADGE",
|
|
211590
|
+
gameId: null,
|
|
211591
|
+
displayName: "First Game Played",
|
|
211592
|
+
description: "Awarded for playing your first game in the Playcademy platform.",
|
|
211593
|
+
type: "badge",
|
|
211594
|
+
isPlaceable: false,
|
|
211595
|
+
imageUrl: "http://playcademy-sandbox.local/first-game-badge.png",
|
|
211596
|
+
metadata: {
|
|
211597
|
+
rarity: "uncommon"
|
|
211598
|
+
}
|
|
211599
|
+
},
|
|
211600
|
+
{
|
|
211601
|
+
id: DEMO_ITEM_IDS2.commonSword,
|
|
211602
|
+
slug: "COMMON_SWORD",
|
|
211603
|
+
gameId: null,
|
|
211604
|
+
displayName: "Common Sword",
|
|
211605
|
+
description: "A basic sword, good for beginners.",
|
|
211606
|
+
type: "unlock",
|
|
211607
|
+
isPlaceable: false,
|
|
211608
|
+
imageUrl: "http://playcademy-sandbox.local/common-sword.png",
|
|
211609
|
+
metadata: undefined
|
|
211610
|
+
},
|
|
211611
|
+
{
|
|
211612
|
+
id: DEMO_ITEM_IDS2.smallHealthPotion,
|
|
211613
|
+
slug: "SMALL_HEALTH_POTION",
|
|
211614
|
+
gameId: null,
|
|
211615
|
+
displayName: "Small Health Potion",
|
|
211616
|
+
description: "Restores a small amount of health.",
|
|
211617
|
+
type: "other",
|
|
211618
|
+
isPlaceable: false,
|
|
211619
|
+
imageUrl: "http://playcademy-sandbox.local/small-health-potion.png",
|
|
211620
|
+
metadata: undefined
|
|
211621
|
+
},
|
|
211622
|
+
{
|
|
211623
|
+
id: DEMO_ITEM_IDS2.smallBackpack,
|
|
211624
|
+
slug: "SMALL_BACKPACK",
|
|
211625
|
+
gameId: null,
|
|
211626
|
+
displayName: "Small Backpack",
|
|
211627
|
+
description: "Increases your inventory capacity by 5 slots.",
|
|
211628
|
+
type: "upgrade",
|
|
211629
|
+
isPlaceable: false,
|
|
211630
|
+
imageUrl: "http://playcademy-sandbox.local/small-backpack.png",
|
|
211631
|
+
metadata: undefined
|
|
211632
|
+
}
|
|
211633
|
+
];
|
|
211634
|
+
var SAMPLE_INVENTORY2 = [
|
|
211635
|
+
{
|
|
211636
|
+
id: "20000000-0000-0000-0000-000000000001",
|
|
211637
|
+
userId: DEMO_USER2.id,
|
|
211638
|
+
itemId: PLAYCADEMY_CREDITS_ID2,
|
|
211639
|
+
quantity: 1000
|
|
211640
|
+
}
|
|
211641
|
+
];
|
|
211374
211642
|
|
|
211375
|
-
|
|
211376
|
-
|
|
211377
|
-
|
|
211378
|
-
|
|
211379
|
-
|
|
211380
|
-
|
|
211381
|
-
|
|
211643
|
+
// src/lib/sandbox/token.ts
|
|
211644
|
+
var ROLE_TO_USER_ID = {
|
|
211645
|
+
player: DEMO_USER_IDS2.player,
|
|
211646
|
+
developer: DEMO_USER_IDS2.developer,
|
|
211647
|
+
admin: DEMO_USER_IDS2.admin
|
|
211648
|
+
};
|
|
211649
|
+
function createSandboxGameToken(gameSlug, role = "player") {
|
|
211650
|
+
const header = { alg: "none", typ: "sandbox" };
|
|
211651
|
+
const payload = {
|
|
211652
|
+
sub: gameSlug,
|
|
211653
|
+
uid: ROLE_TO_USER_ID[role],
|
|
211654
|
+
iat: Math.floor(Date.now() / 1000)
|
|
211655
|
+
};
|
|
211656
|
+
const encode3 = (obj) => btoa(JSON.stringify(obj));
|
|
211657
|
+
return `${encode3(header)}.${encode3(payload)}.sandbox`;
|
|
211658
|
+
}
|
|
211382
211659
|
|
|
211383
|
-
// src/shells/shell
|
|
211384
|
-
var
|
|
211660
|
+
// src/shells/shell.html
|
|
211661
|
+
var shell_default = `<!doctype html>
|
|
211385
211662
|
<html lang="en">
|
|
211386
211663
|
<head>
|
|
211387
211664
|
<meta charset="UTF-8" />
|
|
@@ -211441,16 +211718,16 @@ var shell_with_corner_badge_default = `<!doctype html>
|
|
|
211441
211718
|
<script type="module">
|
|
211442
211719
|
import { MessageEvents, messaging } from '@playcademy/sdk'
|
|
211443
211720
|
|
|
211444
|
-
// Config (injected by vite plugin)
|
|
211445
211721
|
const CONFIG = {
|
|
211446
211722
|
sandboxUrl: '{{SANDBOX_URL}}',
|
|
211447
211723
|
gameId: '{{GAME_ID}}',
|
|
211724
|
+
gameToken: '{{GAME_TOKEN}}',
|
|
211448
211725
|
gameUrl: '{{GAME_URL}}' || undefined,
|
|
211449
211726
|
realtimeUrl: '{{REALTIME_URL}}',
|
|
211450
211727
|
timebackJson: '{{TIMEBACK_DATA}}',
|
|
211728
|
+
hideBadge: '{{HIDE_BADGE}}' === 'true',
|
|
211451
211729
|
}
|
|
211452
211730
|
|
|
211453
|
-
// Parse timeback data (role + enrollments)
|
|
211454
211731
|
const timeback = (() => {
|
|
211455
211732
|
try {
|
|
211456
211733
|
return JSON.parse(CONFIG.timebackJson)
|
|
@@ -211459,18 +211736,19 @@ var shell_with_corner_badge_default = `<!doctype html>
|
|
|
211459
211736
|
}
|
|
211460
211737
|
})()
|
|
211461
211738
|
|
|
211462
|
-
// Elements
|
|
211463
211739
|
const badge = document.getElementById('badge')
|
|
211464
211740
|
const frame = document.getElementById('frame')
|
|
211465
211741
|
|
|
211466
|
-
|
|
211742
|
+
if (CONFIG.hideBadge) {
|
|
211743
|
+
badge.classList.add('hidden')
|
|
211744
|
+
}
|
|
211745
|
+
|
|
211467
211746
|
const log = (...args) => window.PLAYCADEMY_DEBUG && console.log('[DevShell]', ...args)
|
|
211468
211747
|
|
|
211469
|
-
// Check sandbox connection
|
|
211470
211748
|
async function checkSandbox() {
|
|
211471
211749
|
try {
|
|
211472
211750
|
const res = await fetch(\`\${CONFIG.sandboxUrl}/api/users/me\`, {
|
|
211473
|
-
headers: { Authorization:
|
|
211751
|
+
headers: { Authorization: \`Bearer \${CONFIG.gameToken}\` },
|
|
211474
211752
|
})
|
|
211475
211753
|
if (!res.ok) throw new Error('Sandbox unavailable')
|
|
211476
211754
|
badge.classList.remove('offline')
|
|
@@ -211484,14 +211762,13 @@ var shell_with_corner_badge_default = `<!doctype html>
|
|
|
211484
211762
|
}
|
|
211485
211763
|
}
|
|
211486
211764
|
|
|
211487
|
-
// Init handshake with game iframe
|
|
211488
211765
|
function initHandshake(timebackData) {
|
|
211489
211766
|
const payload = {
|
|
211490
211767
|
baseUrl: CONFIG.sandboxUrl,
|
|
211491
211768
|
gameUrl: CONFIG.gameUrl,
|
|
211492
211769
|
gameId: CONFIG.gameId,
|
|
211493
211770
|
realtimeUrl: CONFIG.realtimeUrl,
|
|
211494
|
-
token:
|
|
211771
|
+
token: CONFIG.gameToken,
|
|
211495
211772
|
timeback: timebackData,
|
|
211496
211773
|
}
|
|
211497
211774
|
|
|
@@ -211530,7 +211807,6 @@ var shell_with_corner_badge_default = `<!doctype html>
|
|
|
211530
211807
|
frame.src = '/'
|
|
211531
211808
|
}
|
|
211532
211809
|
|
|
211533
|
-
// Bridge messages from game to shell context
|
|
211534
211810
|
window.addEventListener('message', e => {
|
|
211535
211811
|
if (e.source !== frame.contentWindow) return
|
|
211536
211812
|
const { type, ...payload } = e.data || {}
|
|
@@ -211540,21 +211816,18 @@ var shell_with_corner_badge_default = `<!doctype html>
|
|
|
211540
211816
|
}
|
|
211541
211817
|
})
|
|
211542
211818
|
|
|
211543
|
-
// Start
|
|
211544
211819
|
checkSandbox().then(() => initHandshake(timeback))
|
|
211545
211820
|
</script>
|
|
211546
211821
|
</body>
|
|
211547
211822
|
</html>
|
|
211548
|
-
|
|
211549
|
-
|
|
211550
|
-
|
|
211551
211823
|
`;
|
|
211552
211824
|
|
|
211553
211825
|
// src/server/middleware.ts
|
|
211554
|
-
function generateLoaderHTML(sandboxUrl,
|
|
211555
|
-
const
|
|
211556
|
-
const
|
|
211557
|
-
|
|
211826
|
+
function generateLoaderHTML(sandboxUrl, gameSlug, realtimeUrl, options, gameUrl) {
|
|
211827
|
+
const timebackJson = generateTimebackJson(options.timeback);
|
|
211828
|
+
const platformRole = getPlatformRoleOverride() ?? "player";
|
|
211829
|
+
const gameToken = createSandboxGameToken(gameSlug, platformRole);
|
|
211830
|
+
return shell_default.replace(/{{SANDBOX_URL}}/g, sandboxUrl).replace(/{{GAME_ID}}/g, gameSlug).replace(/{{GAME_TOKEN}}/g, gameToken).replace(/{{REALTIME_URL}}/g, realtimeUrl).replace(/{{GAME_URL}}/g, gameUrl || "").replace(/{{TIMEBACK_DATA}}/g, timebackJson).replace(/{{HIDE_BADGE}}/g, String(options.hideBadge));
|
|
211558
211831
|
}
|
|
211559
211832
|
function devServerMiddleware(server, sandbox, gameUrl, options) {
|
|
211560
211833
|
server.middlewares.use("/", (req, res, next) => {
|
|
@@ -211576,69 +211849,166 @@ function devServerMiddleware(server, sandbox, gameUrl, options) {
|
|
|
211576
211849
|
});
|
|
211577
211850
|
}
|
|
211578
211851
|
|
|
211579
|
-
// src/server/
|
|
211580
|
-
|
|
211581
|
-
|
|
211582
|
-
const now2 = new Date;
|
|
211583
|
-
const hours = now2.getHours();
|
|
211584
|
-
const minutes = now2.getMinutes().toString().padStart(2, "0");
|
|
211585
|
-
const seconds = now2.getSeconds().toString().padStart(2, "0");
|
|
211586
|
-
const ampm = hours >= 12 ? "PM" : "AM";
|
|
211587
|
-
const displayHours = hours % 12 || 12;
|
|
211588
|
-
return dim4(`${displayHours}:${minutes}:${seconds} ${ampm}`);
|
|
211589
|
-
}
|
|
211590
|
-
async function recreateSandboxDatabase(options) {
|
|
211852
|
+
// src/server/recreate-sandbox.ts
|
|
211853
|
+
async function recreateSandbox(options) {
|
|
211854
|
+
const { viteConfig, platformModeOptions } = options;
|
|
211591
211855
|
const currentMode = getCurrentMode();
|
|
211592
211856
|
const viteServer = getViteServerRef();
|
|
211857
|
+
const prefix2 = createLogPrefix("playcademy", "sandbox");
|
|
211593
211858
|
if (!viteServer) {
|
|
211594
|
-
|
|
211595
|
-
return;
|
|
211859
|
+
viteConfig.logger.error(`${prefix2} ${import_picocolors6.red("Cannot recreate sandbox database: no Vite server reference")}`);
|
|
211860
|
+
return { success: false, error: "No Vite server reference" };
|
|
211596
211861
|
}
|
|
211597
211862
|
if (currentMode !== "platform") {
|
|
211598
|
-
|
|
211599
|
-
return;
|
|
211863
|
+
viteConfig.logger.warn(`${prefix2} ${import_picocolors6.yellow("can only recreate sandbox database in platform mode (m + enter)")}`);
|
|
211864
|
+
return { success: false, error: "Not in platform mode" };
|
|
211600
211865
|
}
|
|
211601
|
-
|
|
211866
|
+
viteConfig.logger.info(`${prefix2} recreating database...`);
|
|
211602
211867
|
if (serverState.sandbox) {
|
|
211603
211868
|
serverState.sandbox.cleanup();
|
|
211604
211869
|
serverState.sandbox = null;
|
|
211605
211870
|
}
|
|
211606
211871
|
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
211607
|
-
const
|
|
211608
|
-
|
|
211609
|
-
|
|
211610
|
-
|
|
211611
|
-
|
|
211872
|
+
const timebackDisabled = platformModeOptions.timeback === false;
|
|
211873
|
+
const timebackOptions = platformModeOptions.timeback || undefined;
|
|
211874
|
+
const sandbox = await startSandbox(viteConfig, platformModeOptions.startSandbox, {
|
|
211875
|
+
port: platformModeOptions.sandboxPort,
|
|
211876
|
+
verbose: platformModeOptions.verbose,
|
|
211877
|
+
logLevel: platformModeOptions.logLevel,
|
|
211878
|
+
customUrl: platformModeOptions.sandboxUrl,
|
|
211612
211879
|
recreateDb: true,
|
|
211613
|
-
seed:
|
|
211614
|
-
memoryOnly:
|
|
211615
|
-
databasePath:
|
|
211616
|
-
realtimeEnabled:
|
|
211617
|
-
realtimePort:
|
|
211618
|
-
|
|
211880
|
+
seed: platformModeOptions.seed,
|
|
211881
|
+
memoryOnly: platformModeOptions.memoryOnly,
|
|
211882
|
+
databasePath: platformModeOptions.databasePath,
|
|
211883
|
+
realtimeEnabled: platformModeOptions.realtimeEnabled,
|
|
211884
|
+
realtimePort: platformModeOptions.realtimePort,
|
|
211885
|
+
timebackOptions: timebackDisabled ? false : platformModeOptions.timeback
|
|
211619
211886
|
});
|
|
211620
211887
|
serverState.sandbox = sandbox;
|
|
211621
211888
|
if (sandbox.project && serverState.backend) {
|
|
211622
211889
|
const gameUrl = `http://localhost:${serverState.backend.port}`;
|
|
211623
211890
|
devServerMiddleware(viteServer, sandbox, gameUrl, {
|
|
211624
|
-
|
|
211625
|
-
timeback:
|
|
211891
|
+
hideBadge: platformModeOptions.hideBadge,
|
|
211892
|
+
timeback: timebackDisabled ? undefined : {
|
|
211893
|
+
baseCourses: sandbox.project.timebackCourses ?? [],
|
|
211894
|
+
overrides: timebackOptions
|
|
211895
|
+
}
|
|
211626
211896
|
});
|
|
211627
211897
|
}
|
|
211628
|
-
|
|
211898
|
+
viteConfig.logger.info(`${prefix2} ${import_picocolors6.green("database recreated")}`);
|
|
211899
|
+
return { success: true };
|
|
211900
|
+
}
|
|
211901
|
+
|
|
211902
|
+
// src/server/config-watcher.ts
|
|
211903
|
+
var DEBOUNCE_MS = 500;
|
|
211904
|
+
var VITE_CONFIG_NAMES = ["vite.config.ts", "vite.config.js", "vite.config.mjs"];
|
|
211905
|
+
var debounceTimer = null;
|
|
211906
|
+
function findExistingFiles(projectRoot, fileNames) {
|
|
211907
|
+
return fileNames.map((name3) => path6.join(projectRoot, name3)).filter((file) => fs8.existsSync(file));
|
|
211908
|
+
}
|
|
211909
|
+
function createChangeHandler(server, viteConfig, platformModeOptions, watchedFiles) {
|
|
211910
|
+
return async (changedPath) => {
|
|
211911
|
+
const isWatchedFile = watchedFiles.some((file) => path6.resolve(changedPath) === path6.resolve(file));
|
|
211912
|
+
if (!isWatchedFile)
|
|
211913
|
+
return;
|
|
211914
|
+
if (getCurrentMode() !== "platform")
|
|
211915
|
+
return;
|
|
211916
|
+
if (debounceTimer)
|
|
211917
|
+
clearTimeout(debounceTimer);
|
|
211918
|
+
debounceTimer = setTimeout(async () => {
|
|
211919
|
+
await recreateSandbox({
|
|
211920
|
+
viteConfig,
|
|
211921
|
+
platformModeOptions
|
|
211922
|
+
});
|
|
211923
|
+
server.ws.send({ type: "full-reload" });
|
|
211924
|
+
}, DEBOUNCE_MS);
|
|
211925
|
+
};
|
|
211926
|
+
}
|
|
211927
|
+
function setupConfigWatcher(server, viteConfig, platformModeOptions) {
|
|
211928
|
+
const projectRoot = viteConfig.root;
|
|
211929
|
+
const playcademyConfigs = findExistingFiles(projectRoot, CONFIG_FILE_NAMES);
|
|
211930
|
+
const viteConfigs = findExistingFiles(projectRoot, VITE_CONFIG_NAMES);
|
|
211931
|
+
const allConfigFiles = [...playcademyConfigs, ...viteConfigs];
|
|
211932
|
+
if (allConfigFiles.length === 0)
|
|
211933
|
+
return;
|
|
211934
|
+
for (const configFile of allConfigFiles) {
|
|
211935
|
+
server.watcher.add(configFile);
|
|
211936
|
+
}
|
|
211937
|
+
server.watcher.on("change", createChangeHandler(server, viteConfig, platformModeOptions, allConfigFiles));
|
|
211938
|
+
}
|
|
211939
|
+
|
|
211940
|
+
// src/server/hotkeys/cycle-platform-role.ts
|
|
211941
|
+
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
211942
|
+
|
|
211943
|
+
// src/types/internal.ts
|
|
211944
|
+
var TIMEBACK_ROLES = ["student", "parent", "teacher", "administrator"];
|
|
211945
|
+
var PLATFORM_ROLES = ["player", "developer", "admin"];
|
|
211946
|
+
// src/server/hotkeys/cycle-platform-role.ts
|
|
211947
|
+
function cyclePlatformRole(logger) {
|
|
211948
|
+
const currentRole = getPlatformRoleOverride() ?? "player";
|
|
211949
|
+
const currentIndex = PLATFORM_ROLES.indexOf(currentRole);
|
|
211950
|
+
const nextIndex = (currentIndex + 1) % PLATFORM_ROLES.length;
|
|
211951
|
+
const nextRole = PLATFORM_ROLES[nextIndex];
|
|
211952
|
+
const prefix2 = createLogPrefix("playcademy", "user");
|
|
211953
|
+
setPlatformRoleOverride(nextRole);
|
|
211954
|
+
logger.info(`${prefix2} ${import_picocolors7.red(currentRole)} → ${import_picocolors7.green(nextRole)}`);
|
|
211955
|
+
if (getViteServerRef()) {
|
|
211956
|
+
getViteServerRef()?.ws.send({ type: "full-reload", path: "*" });
|
|
211957
|
+
} else {
|
|
211958
|
+
logger.warn(`${prefix2} ${import_picocolors7.yellow("Cannot cycle platform role: no Vite server reference")}`);
|
|
211959
|
+
}
|
|
211960
|
+
}
|
|
211961
|
+
var cyclePlatformRoleHotkey = (options) => ({
|
|
211962
|
+
key: "p",
|
|
211963
|
+
description: `${import_picocolors7.cyan(import_picocolors7.bold("[playcademy]"))} cycle platform role`,
|
|
211964
|
+
action: () => cyclePlatformRole(options.viteConfig.logger)
|
|
211965
|
+
});
|
|
211966
|
+
|
|
211967
|
+
// src/server/hotkeys/cycle-timeback-role.ts
|
|
211968
|
+
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
211969
|
+
var { bold: bold4, cyan: cyan4, green: green4, red: red3, yellow: yellow3 } = import_picocolors8.default;
|
|
211970
|
+
function cycleTimebackRole(logger) {
|
|
211971
|
+
const currentRole = getTimebackRoleOverride() ?? "student";
|
|
211972
|
+
const currentIndex = TIMEBACK_ROLES.indexOf(currentRole);
|
|
211973
|
+
const nextIndex = (currentIndex + 1) % TIMEBACK_ROLES.length;
|
|
211974
|
+
const nextRole = TIMEBACK_ROLES[nextIndex];
|
|
211975
|
+
setTimebackRoleOverride(nextRole);
|
|
211976
|
+
getSandboxRef()?.setRole?.(nextRole);
|
|
211977
|
+
const prefix2 = createLogPrefix("playcademy", "timeback");
|
|
211978
|
+
logger.info(`${prefix2} ${red3(currentRole)} → ${green4(nextRole)}`);
|
|
211979
|
+
if (getViteServerRef()) {
|
|
211980
|
+
getViteServerRef()?.ws.send({ type: "full-reload", path: "*" });
|
|
211981
|
+
} else {
|
|
211982
|
+
logger.warn(`${prefix2} ${yellow3("Cannot cycle TimeBack role: no Vite server reference")}`);
|
|
211983
|
+
}
|
|
211984
|
+
}
|
|
211985
|
+
var cycleTimebackRoleHotkey = (options) => ({
|
|
211986
|
+
key: "t",
|
|
211987
|
+
description: `${cyan4(bold4("[playcademy]"))} cycle Timeback role`,
|
|
211988
|
+
action: () => cycleTimebackRole(options.viteConfig.logger)
|
|
211989
|
+
});
|
|
211990
|
+
|
|
211991
|
+
// src/server/hotkeys/recreate-database.ts
|
|
211992
|
+
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
211993
|
+
var { bold: bold5, cyan: cyan5 } = import_picocolors9.default;
|
|
211994
|
+
async function recreateSandboxDatabase(options) {
|
|
211995
|
+
await recreateSandbox({
|
|
211996
|
+
viteConfig: options.viteConfig,
|
|
211997
|
+
platformModeOptions: options.platformModeOptions
|
|
211998
|
+
});
|
|
211629
211999
|
}
|
|
211630
212000
|
var recreateDatabaseHotkey = (options) => ({
|
|
211631
212001
|
key: "d",
|
|
211632
|
-
description: "recreate sandbox database
|
|
212002
|
+
description: `${cyan5(bold5("[playcademy]"))} recreate sandbox database`,
|
|
211633
212003
|
action: () => recreateSandboxDatabase(options)
|
|
211634
212004
|
});
|
|
211635
212005
|
|
|
211636
212006
|
// src/server/hotkeys/toggle-mode.ts
|
|
211637
|
-
var
|
|
212007
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
211638
212008
|
// package.json
|
|
211639
212009
|
var package_default2 = {
|
|
211640
212010
|
name: "@playcademy/vite-plugin",
|
|
211641
|
-
version: "0.
|
|
212011
|
+
version: "0.2.0",
|
|
211642
212012
|
type: "module",
|
|
211643
212013
|
exports: {
|
|
211644
212014
|
".": {
|
|
@@ -211657,6 +212027,7 @@ var package_default2 = {
|
|
|
211657
212027
|
pub: "bun publish.ts"
|
|
211658
212028
|
},
|
|
211659
212029
|
dependencies: {
|
|
212030
|
+
"@playcademy/utils": "workspace:*",
|
|
211660
212031
|
archiver: "^7.0.1",
|
|
211661
212032
|
picocolors: "^1.1.1",
|
|
211662
212033
|
playcademy: "workspace:*"
|
|
@@ -211681,27 +212052,29 @@ import {
|
|
|
211681
212052
|
} from "playcademy/utils";
|
|
211682
212053
|
|
|
211683
212054
|
// src/lib/backend/hot-reload.ts
|
|
211684
|
-
var
|
|
211685
|
-
|
|
211686
|
-
if (!changedPath)
|
|
211687
|
-
return;
|
|
211688
|
-
if (changedPath.includes("/api/")) {
|
|
211689
|
-
return changedPath.substring(changedPath.indexOf("/api/"));
|
|
211690
|
-
}
|
|
211691
|
-
return changedPath;
|
|
211692
|
-
}
|
|
212055
|
+
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
212056
|
+
import path7 from "node:path";
|
|
211693
212057
|
function createHotReloadCallbacks(viteConfig) {
|
|
212058
|
+
const formatPath = (changedPath) => {
|
|
212059
|
+
if (!changedPath)
|
|
212060
|
+
return;
|
|
212061
|
+
if (changedPath.startsWith(viteConfig.root)) {
|
|
212062
|
+
return path7.relative(viteConfig.root, changedPath);
|
|
212063
|
+
}
|
|
212064
|
+
return changedPath;
|
|
212065
|
+
};
|
|
212066
|
+
const prefix2 = createLogPrefix("playcademy", "backend");
|
|
211694
212067
|
return {
|
|
211695
212068
|
onSuccess: (changedPath) => {
|
|
211696
|
-
const relativePath =
|
|
212069
|
+
const relativePath = formatPath(changedPath);
|
|
211697
212070
|
if (relativePath) {
|
|
211698
|
-
viteConfig.logger.info(`${
|
|
212071
|
+
viteConfig.logger.info(`${prefix2} ${import_picocolors10.green("hmr update")} ${import_picocolors10.dim(relativePath)}`);
|
|
211699
212072
|
} else {
|
|
211700
|
-
viteConfig.logger.info(
|
|
212073
|
+
viteConfig.logger.info(`${prefix2} reloaded`);
|
|
211701
212074
|
}
|
|
211702
212075
|
},
|
|
211703
212076
|
onError: (error2) => {
|
|
211704
|
-
viteConfig.logger.error(
|
|
212077
|
+
viteConfig.logger.error(`${prefix2} reload failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
211705
212078
|
}
|
|
211706
212079
|
};
|
|
211707
212080
|
}
|
|
@@ -211738,79 +212111,101 @@ function setupHotReload(serverRef, options) {
|
|
|
211738
212111
|
return () => watcher.close();
|
|
211739
212112
|
}
|
|
211740
212113
|
async function setupCliDevServer(options) {
|
|
211741
|
-
const {
|
|
212114
|
+
const { port, viteConfig, platformUrl, configPath } = options;
|
|
211742
212115
|
const config2 = await tryLoadConfig(viteConfig, configPath);
|
|
211743
212116
|
if (!config2)
|
|
211744
212117
|
return null;
|
|
211745
212118
|
if (!needsCliDevServer(config2))
|
|
211746
212119
|
return null;
|
|
211747
212120
|
try {
|
|
211748
|
-
const
|
|
211749
|
-
|
|
212121
|
+
const serverOptions = {
|
|
212122
|
+
port,
|
|
212123
|
+
config: config2,
|
|
212124
|
+
platformUrl,
|
|
212125
|
+
viteConfig
|
|
212126
|
+
};
|
|
211750
212127
|
const serverRef = { current: await startServer2(serverOptions) };
|
|
211751
212128
|
const stopHotReload = setupHotReload(serverRef, serverOptions);
|
|
211752
212129
|
return {
|
|
211753
212130
|
server: serverRef.current.server,
|
|
211754
212131
|
port: serverRef.current.port,
|
|
211755
212132
|
stopHotReload,
|
|
211756
|
-
cleanup: () =>
|
|
212133
|
+
cleanup: () => {}
|
|
211757
212134
|
};
|
|
211758
212135
|
} catch (error2) {
|
|
211759
|
-
|
|
212136
|
+
const message3 = error2 instanceof Error ? error2.message : String(error2);
|
|
212137
|
+
viteConfig.logger.error(`Failed to start game backend: ${message3}`);
|
|
211760
212138
|
return null;
|
|
211761
212139
|
}
|
|
211762
212140
|
}
|
|
211763
212141
|
// src/server/platform-mode.ts
|
|
212142
|
+
var BANNER_PRINTED = false;
|
|
212143
|
+
function isCycleableRole(role) {
|
|
212144
|
+
return TIMEBACK_ROLES.includes(role);
|
|
212145
|
+
}
|
|
211764
212146
|
async function configurePlatformMode(server, viteConfig, options) {
|
|
212147
|
+
const timebackDisabled = options.timeback === false;
|
|
212148
|
+
const timebackOptions = options.timeback || undefined;
|
|
212149
|
+
if (timebackOptions?.role && isCycleableRole(timebackOptions.role)) {
|
|
212150
|
+
setTimebackRoleOverride(timebackOptions.role);
|
|
212151
|
+
}
|
|
211765
212152
|
const sandbox = await startSandbox(viteConfig, options.startSandbox, {
|
|
212153
|
+
port: options.sandboxPort,
|
|
211766
212154
|
verbose: options.verbose,
|
|
211767
212155
|
logLevel: options.logLevel,
|
|
211768
212156
|
customUrl: options.sandboxUrl,
|
|
211769
|
-
quiet: true,
|
|
211770
212157
|
recreateDb: options.recreateDb,
|
|
211771
212158
|
seed: options.seed,
|
|
211772
212159
|
memoryOnly: options.memoryOnly,
|
|
211773
212160
|
databasePath: options.databasePath,
|
|
211774
212161
|
realtimeEnabled: options.realtimeEnabled,
|
|
211775
212162
|
realtimePort: options.realtimePort,
|
|
211776
|
-
|
|
211777
|
-
timebackOptions: options.timeback
|
|
212163
|
+
timebackOptions: timebackDisabled ? false : options.timeback
|
|
211778
212164
|
});
|
|
211779
212165
|
serverState.sandbox = sandbox;
|
|
211780
212166
|
const backend = await setupCliDevServer({
|
|
211781
|
-
|
|
212167
|
+
port: options.backendPort,
|
|
211782
212168
|
viteConfig,
|
|
211783
212169
|
platformUrl: sandbox.baseUrl,
|
|
211784
212170
|
configPath: options.configPath
|
|
211785
212171
|
});
|
|
211786
212172
|
serverState.backend = backend;
|
|
211787
212173
|
if (sandbox.project) {
|
|
211788
|
-
|
|
212174
|
+
if (!timebackDisabled) {
|
|
212175
|
+
validateTimebackConfig(viteConfig, timebackOptions);
|
|
212176
|
+
}
|
|
211789
212177
|
const gameUrl = backend ? `http://localhost:${backend.port}` : undefined;
|
|
212178
|
+
const timebackContext = timebackDisabled ? undefined : {
|
|
212179
|
+
baseCourses: sandbox.project.timebackCourses ?? [],
|
|
212180
|
+
overrides: timebackOptions
|
|
212181
|
+
};
|
|
211790
212182
|
devServerMiddleware(server, sandbox, gameUrl, {
|
|
211791
|
-
|
|
211792
|
-
timeback:
|
|
212183
|
+
hideBadge: options.hideBadge,
|
|
212184
|
+
timeback: timebackContext
|
|
212185
|
+
});
|
|
212186
|
+
}
|
|
212187
|
+
if (!BANNER_PRINTED) {
|
|
212188
|
+
server.httpServer?.once("listening", () => {
|
|
212189
|
+
setTimeout(async () => {
|
|
212190
|
+
const projectInfo = await extractProjectInfo(viteConfig, timebackOptions);
|
|
212191
|
+
printBanner(viteConfig, {
|
|
212192
|
+
version: package_default2.version,
|
|
212193
|
+
gameName: projectInfo.slug,
|
|
212194
|
+
sandbox: { port: sandbox.port, enabled: true },
|
|
212195
|
+
backend: createBackendBannerOptions(backend?.port, server.config.server.port),
|
|
212196
|
+
realtimePort: sandbox.realtimePort,
|
|
212197
|
+
timeback: createTimebackBannerOptions(sandbox.timebackMode, projectInfo.timebackCourses?.length)
|
|
212198
|
+
});
|
|
212199
|
+
BANNER_PRINTED = true;
|
|
212200
|
+
}, 100);
|
|
211793
212201
|
});
|
|
211794
212202
|
}
|
|
211795
|
-
server.httpServer?.once("listening", () => {
|
|
211796
|
-
setTimeout(async () => {
|
|
211797
|
-
const projectInfo = await extractProjectInfo(viteConfig, options.timeback);
|
|
211798
|
-
const vitePort = server.config.server.port;
|
|
211799
|
-
printBanner(viteConfig, {
|
|
211800
|
-
sandbox: sandbox.port,
|
|
211801
|
-
backend: backend?.port,
|
|
211802
|
-
realtime: sandbox.realtimePort,
|
|
211803
|
-
vite: vitePort
|
|
211804
|
-
}, projectInfo, package_default2.version);
|
|
211805
|
-
}, 100);
|
|
211806
|
-
});
|
|
211807
212203
|
}
|
|
211808
212204
|
|
|
211809
212205
|
// src/server/standalone-mode.ts
|
|
211810
|
-
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
211811
212206
|
async function configureStandaloneMode(server, viteConfig, options) {
|
|
211812
212207
|
const backend = await setupCliDevServer({
|
|
211813
|
-
|
|
212208
|
+
port: options.backendPort,
|
|
211814
212209
|
viteConfig,
|
|
211815
212210
|
platformUrl: undefined,
|
|
211816
212211
|
configPath: options.configPath
|
|
@@ -211822,33 +212217,23 @@ async function configureStandaloneMode(server, viteConfig, options) {
|
|
|
211822
212217
|
serverState.backend = backend;
|
|
211823
212218
|
server.httpServer?.once("listening", () => {
|
|
211824
212219
|
setTimeout(() => {
|
|
211825
|
-
viteConfig
|
|
211826
|
-
|
|
211827
|
-
|
|
211828
|
-
|
|
211829
|
-
|
|
211830
|
-
viteConfig.logger.info("");
|
|
212220
|
+
printBanner(viteConfig, {
|
|
212221
|
+
version: package_default2.version,
|
|
212222
|
+
sandbox: { enabled: false },
|
|
212223
|
+
backend: { port: backend.port }
|
|
212224
|
+
});
|
|
211831
212225
|
}, 100);
|
|
211832
212226
|
});
|
|
211833
212227
|
}
|
|
211834
212228
|
|
|
211835
212229
|
// src/server/hotkeys/toggle-mode.ts
|
|
211836
|
-
var { bold: bold5, cyan: cyan4, dim: dim6, green: green4, red: red2 } = import_picocolors10.default;
|
|
211837
|
-
function formatTimestamp4() {
|
|
211838
|
-
const now2 = new Date;
|
|
211839
|
-
const hours = now2.getHours();
|
|
211840
|
-
const minutes = now2.getMinutes().toString().padStart(2, "0");
|
|
211841
|
-
const seconds = now2.getSeconds().toString().padStart(2, "0");
|
|
211842
|
-
const ampm = hours >= 12 ? "PM" : "AM";
|
|
211843
|
-
const displayHours = hours % 12 || 12;
|
|
211844
|
-
return dim6(`${displayHours}:${minutes}:${seconds} ${ampm}`);
|
|
211845
|
-
}
|
|
211846
212230
|
async function toggleMode(options) {
|
|
211847
212231
|
const currentMode = getCurrentMode();
|
|
211848
212232
|
const newMode = currentMode === "platform" ? "standalone" : "platform";
|
|
211849
212233
|
const viteServer = getViteServerRef();
|
|
212234
|
+
const prefix2 = createLogPrefix("playcademy");
|
|
211850
212235
|
if (!viteServer) {
|
|
211851
|
-
options.viteConfig.logger.error(`${
|
|
212236
|
+
options.viteConfig.logger.error(`${prefix2} ${import_picocolors11.red("Cannot toggle mode: no Vite server reference")}`);
|
|
211852
212237
|
return;
|
|
211853
212238
|
}
|
|
211854
212239
|
await cleanupServers();
|
|
@@ -211856,17 +212241,17 @@ async function toggleMode(options) {
|
|
|
211856
212241
|
setCurrentMode(newMode);
|
|
211857
212242
|
if (newMode === "standalone") {
|
|
211858
212243
|
await configureStandaloneMode(viteServer, options.viteConfig, {
|
|
211859
|
-
|
|
212244
|
+
backendPort: options.platformModeOptions.backendPort,
|
|
211860
212245
|
configPath: options.platformModeOptions.configPath
|
|
211861
212246
|
});
|
|
211862
212247
|
} else {
|
|
211863
212248
|
await configurePlatformMode(viteServer, options.viteConfig, options.platformModeOptions);
|
|
211864
212249
|
}
|
|
211865
|
-
options.viteConfig.logger.info(`${
|
|
212250
|
+
options.viteConfig.logger.info(`${prefix2} ${import_picocolors11.green("switched to")} ${import_picocolors11.green(import_picocolors11.bold(newMode))} ${import_picocolors11.green("mode")}`);
|
|
211866
212251
|
}
|
|
211867
212252
|
var toggleModeHotkey = (options) => ({
|
|
211868
212253
|
key: "m",
|
|
211869
|
-
description: "toggle platform/standalone mode
|
|
212254
|
+
description: `${import_picocolors11.cyan(import_picocolors11.bold("[playcademy]"))} toggle platform/standalone mode`,
|
|
211870
212255
|
action: () => toggleMode(options)
|
|
211871
212256
|
});
|
|
211872
212257
|
|
|
@@ -211875,6 +212260,7 @@ function getHotkeys(options) {
|
|
|
211875
212260
|
return [
|
|
211876
212261
|
toggleModeHotkey(options),
|
|
211877
212262
|
recreateDatabaseHotkey(options),
|
|
212263
|
+
cyclePlatformRoleHotkey(options),
|
|
211878
212264
|
cycleTimebackRoleHotkey(options)
|
|
211879
212265
|
];
|
|
211880
212266
|
}
|
|
@@ -211907,11 +212293,12 @@ async function configureServerHook(server, context) {
|
|
|
211907
212293
|
setupProcessShutdownHandlers();
|
|
211908
212294
|
if (hasActiveServers()) {
|
|
211909
212295
|
await cleanupServers();
|
|
211910
|
-
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
211911
212296
|
}
|
|
211912
|
-
const
|
|
212297
|
+
const backendPort = context.backendPort ?? DEFAULT_PORTS3.BACKEND;
|
|
212298
|
+
const sandboxPort = context.sandboxPort ?? DEFAULT_PORTS3.SANDBOX;
|
|
211913
212299
|
const platformModeOptions = {
|
|
211914
212300
|
startSandbox: context.options.startSandbox,
|
|
212301
|
+
sandboxPort,
|
|
211915
212302
|
verbose: context.options.verbose,
|
|
211916
212303
|
logLevel: context.options.logLevel,
|
|
211917
212304
|
sandboxUrl: context.options.sandboxUrl,
|
|
@@ -211921,18 +212308,19 @@ async function configureServerHook(server, context) {
|
|
|
211921
212308
|
databasePath: context.options.databasePath,
|
|
211922
212309
|
realtimeEnabled: context.options.realtimeEnabled,
|
|
211923
212310
|
realtimePort: context.options.realtimePort,
|
|
211924
|
-
|
|
211925
|
-
|
|
212311
|
+
hideBadge: context.options.hideBadge,
|
|
212312
|
+
backendPort,
|
|
211926
212313
|
configPath: context.options.configPath,
|
|
211927
212314
|
timeback: context.options.timeback
|
|
211928
212315
|
};
|
|
211929
212316
|
if (context.options.mode === "standalone") {
|
|
211930
212317
|
await configureStandaloneMode(server, context.viteConfig, {
|
|
211931
|
-
|
|
212318
|
+
backendPort,
|
|
211932
212319
|
configPath: context.options.configPath
|
|
211933
212320
|
});
|
|
211934
212321
|
} else {
|
|
211935
212322
|
await configurePlatformMode(server, context.viteConfig, platformModeOptions);
|
|
212323
|
+
setupConfigWatcher(server, context.viteConfig, platformModeOptions);
|
|
211936
212324
|
}
|
|
211937
212325
|
const originalBindCLIShortcuts = server.bindCLIShortcuts?.bind(server);
|
|
211938
212326
|
if (originalBindCLIShortcuts) {
|
|
@@ -211952,12 +212340,12 @@ async function configureServerHook(server, context) {
|
|
|
211952
212340
|
}
|
|
211953
212341
|
|
|
211954
212342
|
// src/hooks/write-bundle.ts
|
|
211955
|
-
import
|
|
212343
|
+
import path8 from "node:path";
|
|
211956
212344
|
async function writeBundleHook(context) {
|
|
211957
212345
|
if (!context.viteConfig) {
|
|
211958
212346
|
throw new Error("[Playcademy] Vite config not resolved before writeBundle");
|
|
211959
212347
|
}
|
|
211960
|
-
const outDir = context.viteConfig.build.outDir ||
|
|
212348
|
+
const outDir = context.viteConfig.build.outDir || path8.join(process.cwd(), "dist");
|
|
211961
212349
|
try {
|
|
211962
212350
|
await generatePlaycademyManifest(context.viteConfig, outDir, context.buildOutputs);
|
|
211963
212351
|
if (context.options.autoZip) {
|
|
@@ -211976,7 +212364,7 @@ async function writeBundleHook(context) {
|
|
|
211976
212364
|
function resolveOptions(options) {
|
|
211977
212365
|
const exportOptions = options.export ?? {};
|
|
211978
212366
|
const sandboxOptions = options.sandbox ?? {};
|
|
211979
|
-
const
|
|
212367
|
+
const displayOptions = options.display ?? {};
|
|
211980
212368
|
const realtimeOptions = sandboxOptions.realtime ?? {};
|
|
211981
212369
|
return {
|
|
211982
212370
|
configPath: options.configPath,
|
|
@@ -211992,7 +212380,7 @@ function resolveOptions(options) {
|
|
|
211992
212380
|
databasePath: sandboxOptions.databasePath,
|
|
211993
212381
|
realtimeEnabled: realtimeOptions.enabled ?? false,
|
|
211994
212382
|
realtimePort: realtimeOptions.port,
|
|
211995
|
-
|
|
212383
|
+
hideBadge: displayOptions.hideBadge ?? false,
|
|
211996
212384
|
timeback: options.timeback
|
|
211997
212385
|
};
|
|
211998
212386
|
}
|
|
@@ -212001,6 +212389,7 @@ function createPluginContext(options) {
|
|
|
212001
212389
|
options: resolveOptions(options),
|
|
212002
212390
|
viteConfig: null,
|
|
212003
212391
|
backendPort: null,
|
|
212392
|
+
sandboxPort: null,
|
|
212004
212393
|
buildOutputs: {}
|
|
212005
212394
|
};
|
|
212006
212395
|
}
|