playcademy 0.27.1-beta.2 → 0.27.1-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bucket.js CHANGED
@@ -94,7 +94,7 @@ var DEFAULT_API_ROUTES_DIRECTORY = join2(SERVER_ROOT_DIRECTORY, "api");
94
94
  // ../better-auth/package.json
95
95
  var package_default = {
96
96
  name: "@playcademy/better-auth",
97
- version: "0.0.20-beta.1",
97
+ version: "0.0.20-beta.2",
98
98
  type: "module",
99
99
  exports: {
100
100
  "./server": {
package/dist/cli.js CHANGED
@@ -1196,7 +1196,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
1196
1196
  // ../better-auth/package.json
1197
1197
  var package_default = {
1198
1198
  name: "@playcademy/better-auth",
1199
- version: "0.0.20-beta.1",
1199
+ version: "0.0.20-beta.2",
1200
1200
  type: "module",
1201
1201
  exports: {
1202
1202
  "./server": {
@@ -2951,7 +2951,7 @@ import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as re
2951
2951
  import { join as join13 } from "node:path";
2952
2952
 
2953
2953
  // src/version.ts
2954
- var cliVersion = false ? "0.0.0-dev" : "0.27.1-beta.2";
2954
+ var cliVersion = false ? "0.0.0-dev" : "0.27.1-beta.3";
2955
2955
 
2956
2956
  // src/lib/init/database.ts
2957
2957
  var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
package/dist/constants.js CHANGED
@@ -20,7 +20,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
20
20
  // ../better-auth/package.json
21
21
  var package_default = {
22
22
  name: "@playcademy/better-auth",
23
- version: "0.0.20-beta.1",
23
+ version: "0.0.20-beta.2",
24
24
  type: "module",
25
25
  exports: {
26
26
  "./server": {
package/dist/db.js CHANGED
@@ -36,7 +36,7 @@ var DEFAULT_API_ROUTES_DIRECTORY = join2(SERVER_ROOT_DIRECTORY, "api");
36
36
  // ../better-auth/package.json
37
37
  var package_default = {
38
38
  name: "@playcademy/better-auth",
39
- version: "0.0.20-beta.1",
39
+ version: "0.0.20-beta.2",
40
40
  type: "module",
41
41
  exports: {
42
42
  "./server": {
package/dist/index.d.ts CHANGED
@@ -840,6 +840,7 @@ interface DeploymentContext {
840
840
  verbose: boolean;
841
841
  debug: boolean;
842
842
  json: boolean;
843
+ allowRollback?: boolean;
843
844
  compatibilityDate?: string;
844
845
  }
845
846
  /**
package/dist/index.js CHANGED
@@ -326,7 +326,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
326
326
  // ../better-auth/package.json
327
327
  var package_default = {
328
328
  name: "@playcademy/better-auth",
329
- version: "0.0.20-beta.1",
329
+ version: "0.0.20-beta.2",
330
330
  type: "module",
331
331
  exports: {
332
332
  "./server": {
@@ -3907,7 +3907,7 @@ async function checkbox(config) {
3907
3907
  // src/lib/core/subprocess.ts
3908
3908
  import { spawn } from "node:child_process";
3909
3909
  function runShell(command, options = {}) {
3910
- return new Promise((resolve14, reject) => {
3910
+ return new Promise((resolve15, reject) => {
3911
3911
  const env = { ...options.env ?? process.env };
3912
3912
  delete env.ESBUILD_BINARY_PATH;
3913
3913
  const child = spawn(command, {
@@ -3927,7 +3927,7 @@ function runShell(command, options = {}) {
3927
3927
  child.on("error", reject);
3928
3928
  child.on("close", (code) => {
3929
3929
  if (code === 0) {
3930
- resolve14();
3930
+ resolve15();
3931
3931
  } else {
3932
3932
  reject(
3933
3933
  Object.assign(new Error(`Command failed: ${command}`), {
@@ -4140,7 +4140,7 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as rea
4140
4140
  import { join as join13 } from "node:path";
4141
4141
 
4142
4142
  // src/version.ts
4143
- var cliVersion = false ? "0.0.0-dev" : "0.27.1-beta.2";
4143
+ var cliVersion = false ? "0.0.0-dev" : "0.27.1-beta.3";
4144
4144
 
4145
4145
  // src/lib/init/database.ts
4146
4146
  var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
@@ -7362,14 +7362,14 @@ function readServerInfo(type, projectRoot) {
7362
7362
  return servers[0] || null;
7363
7363
  }
7364
7364
  async function isPortInUse(port) {
7365
- return new Promise((resolve14) => {
7365
+ return new Promise((resolve15) => {
7366
7366
  const server = createServer();
7367
7367
  server.once("error", () => {
7368
- resolve14(true);
7368
+ resolve15(true);
7369
7369
  });
7370
7370
  server.once("listening", () => {
7371
7371
  server.close();
7372
- resolve14(false);
7372
+ resolve15(false);
7373
7373
  });
7374
7374
  server.listen(port, "0.0.0.0");
7375
7375
  });
@@ -7383,7 +7383,7 @@ async function waitForPort(port, timeoutMs = 5e3) {
7383
7383
  Stop the other server or specify a different port with --port <number>.`
7384
7384
  );
7385
7385
  }
7386
- await new Promise((resolve14) => setTimeout(resolve14, 100));
7386
+ await new Promise((resolve15) => setTimeout(resolve15, 100));
7387
7387
  }
7388
7388
  }
7389
7389
 
@@ -11095,7 +11095,8 @@ function normalizeVersion(version3) {
11095
11095
  return trimmed.replace(/^[vV]/, "");
11096
11096
  }
11097
11097
  function parseVersion(v) {
11098
- const [version3, ...pre] = v.split("-");
11098
+ const [versionWithPrerelease] = v.split("+");
11099
+ const [version3, ...pre] = versionWithPrerelease.split("-");
11099
11100
  const parts = version3.split(".").map(Number);
11100
11101
  if (parts.some((n) => Number.isNaN(n))) {
11101
11102
  return null;
@@ -11683,6 +11684,83 @@ function displayDeploymentDiff(options) {
11683
11684
  // src/lib/deploy/interaction.ts
11684
11685
  import { join as join41 } from "path";
11685
11686
 
11687
+ // src/lib/deploy/rollback-check.ts
11688
+ import { readFile as readFile6 } from "node:fs/promises";
11689
+ import { resolve as resolve12 } from "node:path";
11690
+ import JSZip2 from "jszip";
11691
+ var PLAYCADEMY_MANIFEST_FILE = "playcademy.manifest.json";
11692
+ var TRACKED_VERSIONS = [
11693
+ {
11694
+ key: "gameVersion",
11695
+ displayName: "game",
11696
+ read: (manifest) => manifest.gameVersion
11697
+ },
11698
+ {
11699
+ key: "vitePlugin",
11700
+ displayName: "@playcademy/vite-plugin",
11701
+ read: (manifest) => manifest.versions.vitePlugin
11702
+ },
11703
+ {
11704
+ key: "sdk",
11705
+ displayName: "@playcademy/sdk",
11706
+ read: (manifest) => manifest.versions.sdk
11707
+ }
11708
+ ];
11709
+ function shouldBlockVersionRollback(args) {
11710
+ return args.promptless && !args.allowRollback;
11711
+ }
11712
+ function rollbackDisplayName(name) {
11713
+ return TRACKED_VERSIONS.find((entry) => entry.key === name).displayName;
11714
+ }
11715
+ function isManifestV2(manifest) {
11716
+ return isRecord(manifest) && manifest.version === "2" && isRecord(manifest.versions);
11717
+ }
11718
+ async function readBuildManifest(buildPath) {
11719
+ try {
11720
+ const zip = await JSZip2.loadAsync(await readFile6(resolve12(buildPath)));
11721
+ const manifestFile = zip.file(PLAYCADEMY_MANIFEST_FILE) ?? Object.values(zip.files).find(
11722
+ (file) => !file.dir && file.name.endsWith(`/${PLAYCADEMY_MANIFEST_FILE}`)
11723
+ );
11724
+ if (!manifestFile) {
11725
+ return null;
11726
+ }
11727
+ const parsed = JSON.parse(await manifestFile.async("string"));
11728
+ return isManifestV2(parsed) ? parsed : null;
11729
+ } catch {
11730
+ return null;
11731
+ }
11732
+ }
11733
+ function addRegression(regressions, name, live, proposed) {
11734
+ if (typeof live !== "string" || typeof proposed !== "string" || live.trim().length === 0 || proposed.trim().length === 0) {
11735
+ return;
11736
+ }
11737
+ if (compareVersions(proposed, live) < 0) {
11738
+ regressions.push({ name, live, proposed });
11739
+ }
11740
+ }
11741
+ function findVersionRollbacks(live, proposed) {
11742
+ const regressions = [];
11743
+ for (const { key, read: read2 } of TRACKED_VERSIONS) {
11744
+ addRegression(regressions, key, read2(live), read2(proposed));
11745
+ }
11746
+ return regressions;
11747
+ }
11748
+ async function detectVersionRollback(context2, plan, fetchLiveGame) {
11749
+ if (!plan.shouldUploadBuild || !context2.config.buildPath) {
11750
+ return null;
11751
+ }
11752
+ const [liveGame, proposedManifest] = await Promise.all([
11753
+ fetchLiveGame(),
11754
+ readBuildManifest(context2.config.buildPath)
11755
+ ]);
11756
+ const liveManifest = liveGame?.manifest ?? null;
11757
+ if (!isManifestV2(liveManifest) || !proposedManifest) {
11758
+ return null;
11759
+ }
11760
+ const regressions = findVersionRollbacks(liveManifest, proposedManifest);
11761
+ return regressions.length > 0 ? { regressions } : null;
11762
+ }
11763
+
11686
11764
  // src/lib/deploy/schema.ts
11687
11765
  import { existsSync as existsSync27 } from "fs";
11688
11766
  import { createRequire as createRequire2 } from "module";
@@ -11690,7 +11768,7 @@ import { join as join39 } from "path";
11690
11768
 
11691
11769
  // src/lib/deploy/migrations.ts
11692
11770
  import { existsSync as existsSync26 } from "fs";
11693
- import { readFile as readFile6 } from "fs/promises";
11771
+ import { readFile as readFile7 } from "fs/promises";
11694
11772
  import { join as join38 } from "path";
11695
11773
  import { bold as bold8 } from "colorette";
11696
11774
 
@@ -11759,7 +11837,7 @@ async function readMigrationJournal(options = {}) {
11759
11837
  }
11760
11838
  const journalPath = join38(migrationsDir, META_DIR, JOURNAL_FILE);
11761
11839
  try {
11762
- const raw = await readFile6(journalPath, "utf8");
11840
+ const raw = await readFile7(journalPath, "utf8");
11763
11841
  const journal = JSON.parse(raw);
11764
11842
  if (!Array.isArray(journal.entries)) {
11765
11843
  if (!options.quiet) {
@@ -11816,7 +11894,7 @@ async function getUnappliedMigrations(lastAppliedTag, options = {}) {
11816
11894
  The journal references migration "${entry.tag}" but the .sql file is missing.`
11817
11895
  );
11818
11896
  }
11819
- const raw = await readFile6(sqlPath, "utf8");
11897
+ const raw = await readFile7(sqlPath, "utf8");
11820
11898
  const sql3 = raw.replace(STATEMENT_BREAKPOINT_RE, "").trim();
11821
11899
  results.push({ tag: entry.tag, sql: sql3 });
11822
11900
  }
@@ -12153,12 +12231,12 @@ function getLocalOverrideCourseChangeCounts(snapshot) {
12153
12231
 
12154
12232
  // src/lib/deploy/validate.ts
12155
12233
  import { existsSync as existsSync28 } from "fs";
12156
- import { resolve as resolve12 } from "path";
12234
+ import { resolve as resolve13 } from "path";
12157
12235
  function validateBuildPath(path4) {
12158
12236
  if (!path4.trim()) {
12159
12237
  return "Build path is required";
12160
12238
  }
12161
- const resolvedPath = resolve12(path4.trim());
12239
+ const resolvedPath = resolve13(path4.trim());
12162
12240
  if (!existsSync28(resolvedPath)) {
12163
12241
  return `Build path not found: ${path4.trim()}`;
12164
12242
  }
@@ -12413,7 +12491,9 @@ async function confirmUpdateExistingDeploymentPlan(plan, context2) {
12413
12491
  const previousResources = context2.previousResources || [];
12414
12492
  const addedResources = currentResources.filter((r) => !previousResources.includes(r));
12415
12493
  const removedResources = previousResources.filter((r) => !currentResources.includes(r));
12416
- const drift = await detectDashboardDrift(context2, plan);
12494
+ const fetchRemoteGame = remoteGameFetcher(context2);
12495
+ const versionRollbackPromise = context2.json && context2.allowRollback ? null : detectVersionRollback(context2, plan, fetchRemoteGame);
12496
+ const drift = await detectDashboardDrift(context2, plan, fetchRemoteGame);
12417
12497
  let timebackDrift;
12418
12498
  try {
12419
12499
  timebackDrift = await detectDeployTimebackDrift(context2);
@@ -12428,6 +12508,7 @@ async function confirmUpdateExistingDeploymentPlan(plan, context2) {
12428
12508
  return false;
12429
12509
  }
12430
12510
  const driftLabels = drift ? new Set(drift.rows.map((r) => r.label)) : void 0;
12511
+ const versionRollback = await versionRollbackPromise;
12431
12512
  const configDiff = plan.changes.config ? calculateConfigDiff(context2.existingGame, config) : {};
12432
12513
  const integrationMetadata = timebackDrift ? plan.changes.integrationsMetadata?.filter((integration) => integration.name !== "TimeBack") : plan.changes.integrationsMetadata;
12433
12514
  const diffOptions = {
@@ -12464,27 +12545,31 @@ async function confirmUpdateExistingDeploymentPlan(plan, context2) {
12464
12545
  const hasConfigDiff = Object.keys(configDiff).length > 0;
12465
12546
  const hasConfigSection = Boolean(drift && hasConfigDiff);
12466
12547
  let driftDecision;
12548
+ if (isNonInteractive()) {
12549
+ return confirmNonInteractiveUpdateExistingDeploymentPlan({
12550
+ context: context2,
12551
+ drift,
12552
+ timebackDrift,
12553
+ versionRollback,
12554
+ diffOptions,
12555
+ hasConfigSection
12556
+ });
12557
+ }
12558
+ if (versionRollback && !await confirmInteractiveVersionRollback(context2, versionRollback)) {
12559
+ return false;
12560
+ }
12467
12561
  if (hasConfigSection && !context2.json) {
12468
12562
  displayDeploymentDiff({
12469
12563
  ...diffOptions,
12470
12564
  section: "config"
12471
12565
  });
12472
12566
  }
12473
- if (drift && !isNonInteractive()) {
12567
+ if (drift) {
12474
12568
  driftDecision = await promptDashboardDriftDecision({ context: context2, drift });
12475
12569
  if (driftDecision === "cancel") {
12476
12570
  return false;
12477
12571
  }
12478
12572
  }
12479
- if (isNonInteractive()) {
12480
- return confirmNonInteractiveUpdateExistingDeploymentPlan({
12481
- context: context2,
12482
- drift,
12483
- timebackDrift,
12484
- diffOptions,
12485
- hasConfigSection
12486
- });
12487
- }
12488
12573
  const timebackDecision = timebackDrift ? await promptDeployTimebackDriftDecision({
12489
12574
  context: context2,
12490
12575
  snapshot: timebackDrift
@@ -12507,7 +12592,16 @@ async function confirmUpdateExistingDeploymentPlan(plan, context2) {
12507
12592
  });
12508
12593
  }
12509
12594
  function confirmNonInteractiveUpdateExistingDeploymentPlan(args) {
12510
- const { context: context2, drift, timebackDrift, diffOptions, hasConfigSection } = args;
12595
+ const { context: context2, drift, timebackDrift, versionRollback, diffOptions, hasConfigSection } = args;
12596
+ if (hasConfigSection && !context2.json) {
12597
+ displayDeploymentDiff({
12598
+ ...diffOptions,
12599
+ section: "config"
12600
+ });
12601
+ }
12602
+ if (versionRollback && shouldBlockVersionRollback({ allowRollback: context2.allowRollback, promptless: true })) {
12603
+ return blockVersionRollback(context2, versionRollback);
12604
+ }
12511
12605
  if (timebackDrift) {
12512
12606
  if (context2.json) {
12513
12607
  context2.cancellationReason = "TimeBack config drift detected between local config and the platform. Re-run interactively to choose whether to apply local metadata changes or sync local config from the dashboard.";
@@ -12520,6 +12614,10 @@ function confirmNonInteractiveUpdateExistingDeploymentPlan(args) {
12520
12614
  if (drift && !context2.json) {
12521
12615
  logger.remark("Dashboard edits will be overwritten by local config", 1);
12522
12616
  }
12617
+ if (versionRollback) {
12618
+ reportVersionRollback(versionRollback);
12619
+ logger.remark("Rollback allowed by --allow-rollback", 1);
12620
+ }
12523
12621
  if (!context2.json) {
12524
12622
  logger.newLine();
12525
12623
  displayDeploymentDiff({
@@ -12537,6 +12635,23 @@ async function confirmUpdateExistingProject(config) {
12537
12635
  nonInteractiveHint: "Pass --yes to confirm deployment update."
12538
12636
  });
12539
12637
  }
12638
+ async function confirmInteractiveVersionRollback(context2, snapshot) {
12639
+ if (shouldBlockVersionRollback({
12640
+ allowRollback: context2.allowRollback,
12641
+ promptless: shouldAssumeYes()
12642
+ })) {
12643
+ return blockVersionRollback(context2, snapshot);
12644
+ }
12645
+ return await confirmVersionRollbackReview({ config: context2.config, snapshot });
12646
+ }
12647
+ async function confirmVersionRollbackReview(args) {
12648
+ const { config, snapshot } = args;
12649
+ reportVersionRollback(snapshot);
12650
+ return await confirm({
12651
+ message: `Continue with rollback for ${config.displayName}?`,
12652
+ default: false
12653
+ });
12654
+ }
12540
12655
  async function confirmUpdateAfterDriftDecision(args) {
12541
12656
  const { context: context2, config, drift, driftDecision, timebackDrift, timebackDecision } = args;
12542
12657
  if (driftDecision === "cancel") {
@@ -12567,6 +12682,30 @@ async function confirmUpdateAfterDriftDecision(args) {
12567
12682
  }
12568
12683
  return true;
12569
12684
  }
12685
+ function reportVersionRollback(snapshot) {
12686
+ logger.admonition("warning", "Version Rollback Detected", [
12687
+ "The build you are about to deploy is older than the live deployment:",
12688
+ "",
12689
+ ...snapshot.regressions.map(
12690
+ (regression) => logger.change(
12691
+ regression.live,
12692
+ regression.proposed,
12693
+ rollbackDisplayName(regression.name)
12694
+ )
12695
+ )
12696
+ ]);
12697
+ }
12698
+ function blockVersionRollback(context2, snapshot) {
12699
+ reportVersionRollback(snapshot);
12700
+ logger.admonition("warning", "Deploy Blocked", [
12701
+ "This deploy would roll back one or more live versions.",
12702
+ "Pass `--allow-rollback` if the rollback is intentional."
12703
+ ]);
12704
+ context2.cancellationReason = "Version rollback detected. Pass --allow-rollback if the rollback is intentional.";
12705
+ context2.cancellationHandled = true;
12706
+ process.exitCode = 1;
12707
+ return false;
12708
+ }
12570
12709
  function forceIntegrationConfigSync(context2, integrationKey) {
12571
12710
  context2.forceIntegrationConfigSync = [
12572
12711
  .../* @__PURE__ */ new Set([...context2.forceIntegrationConfigSync ?? [], integrationKey])
@@ -12602,23 +12741,37 @@ function getCurrentResources(context2) {
12602
12741
  }
12603
12742
  return resources;
12604
12743
  }
12605
- async function detectDashboardDrift(context2, plan) {
12744
+ function remoteGameFetcher(context2) {
12745
+ let fetched;
12746
+ return () => {
12747
+ fetched ??= (async () => {
12748
+ const gameIdOrSlug = context2.existingGame?.id ?? context2.deployedGameInfo?.gameId ?? context2.config.slug;
12749
+ if (!gameIdOrSlug) {
12750
+ return null;
12751
+ }
12752
+ try {
12753
+ return await context2.client.games.fetch(gameIdOrSlug, { force: true });
12754
+ } catch {
12755
+ return null;
12756
+ }
12757
+ })();
12758
+ return fetched;
12759
+ };
12760
+ }
12761
+ async function detectDashboardDrift(context2, plan, fetchRemoteGame) {
12606
12762
  if (!context2.config.slug || skipsDeployGameDueToSecretsOnly(context2, plan)) {
12607
12763
  return null;
12608
12764
  }
12609
- try {
12610
- const remoteGame = await context2.client.games.fetch(context2.config.slug, {
12611
- force: true
12612
- });
12613
- const localPayload = buildDeployGameMetadataPayload(context2.config);
12614
- const rows = getDashboardMetadataDriftRows(remoteGame, localPayload);
12615
- if (rows.length === 0) {
12616
- return null;
12617
- }
12618
- return { rows, remoteGame };
12619
- } catch {
12765
+ const remoteGame = await fetchRemoteGame();
12766
+ if (!remoteGame) {
12620
12767
  return null;
12621
12768
  }
12769
+ const localPayload = buildDeployGameMetadataPayload(context2.config);
12770
+ const rows = getDashboardMetadataDriftRows(remoteGame, localPayload);
12771
+ if (rows.length === 0) {
12772
+ return null;
12773
+ }
12774
+ return { rows, remoteGame };
12622
12775
  }
12623
12776
  function formatDriftRowValue(value) {
12624
12777
  if (value === null || value === void 0 || value === "") {
@@ -13536,6 +13689,7 @@ async function prepareDeploymentContext(options) {
13536
13689
  verbose: options.verbose ?? false,
13537
13690
  debug: options.debug ?? false,
13538
13691
  json: options.json ?? false,
13692
+ allowRollback: options.allowRollback ?? false,
13539
13693
  compatibilityDate: options.compatibilityDate,
13540
13694
  localSecrets,
13541
13695
  remoteSecretKeys
@@ -13757,12 +13911,12 @@ function hasOptionalFieldsMissing(missing) {
13757
13911
 
13758
13912
  // src/lib/deploy/steps.ts
13759
13913
  import { existsSync as existsSync29 } from "fs";
13760
- import { readFile as readFile7 } from "fs/promises";
13761
- import { basename as basename4, join as join43, resolve as resolve13 } from "path";
13914
+ import { readFile as readFile8 } from "fs/promises";
13915
+ import { basename as basename4, join as join43, resolve as resolve14 } from "path";
13762
13916
  async function prepareBuildFile(buildPath) {
13763
- const resolvedPath = resolve13(buildPath);
13917
+ const resolvedPath = resolve14(buildPath);
13764
13918
  if (resolvedPath.endsWith(".zip") && existsSync29(resolvedPath)) {
13765
- const buffer = await readFile7(resolvedPath);
13919
+ const buffer = await readFile8(resolvedPath);
13766
13920
  const uint8Array = new Uint8Array(buffer);
13767
13921
  const blob = new Blob([uint8Array], { type: "application/zip" });
13768
13922
  return new File([blob], basename4(resolvedPath), { type: "application/zip" });
@@ -14058,7 +14212,7 @@ async function findPackageUpdates(workspace) {
14058
14212
  import { dim as dim8 } from "colorette";
14059
14213
 
14060
14214
  // src/lib/nudge/state.ts
14061
- import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile6 } from "node:fs/promises";
14215
+ import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile6 } from "node:fs/promises";
14062
14216
  import { join as join44 } from "node:path";
14063
14217
  var NUDGE_STATE_FILE = "nudge-state.json";
14064
14218
  var NUDGE_COOLDOWN_MS = 24 * 60 * 60 * 1e3;
@@ -14067,7 +14221,7 @@ function getStatePath() {
14067
14221
  }
14068
14222
  async function loadNudgeState() {
14069
14223
  try {
14070
- return JSON.parse(await readFile8(getStatePath(), "utf8"));
14224
+ return JSON.parse(await readFile9(getStatePath(), "utf8"));
14071
14225
  } catch {
14072
14226
  return {};
14073
14227
  }
@@ -14686,7 +14840,7 @@ function getErrorHtml(error) {
14686
14840
 
14687
14841
  // src/lib/auth/http-server/server.ts
14688
14842
  async function startCallbackServer(timeoutMs) {
14689
- return new Promise((resolve14) => {
14843
+ return new Promise((resolve15) => {
14690
14844
  let server = null;
14691
14845
  let timeoutId = null;
14692
14846
  function cleanup(callback) {
@@ -14704,7 +14858,7 @@ async function startCallbackServer(timeoutMs) {
14704
14858
  }
14705
14859
  timeoutId = setTimeout(() => {
14706
14860
  cleanup(() => {
14707
- resolve14({
14861
+ resolve15({
14708
14862
  success: false,
14709
14863
  error: "Authentication timed out. Please try again."
14710
14864
  });
@@ -14718,7 +14872,7 @@ async function startCallbackServer(timeoutMs) {
14718
14872
  const userId = url.searchParams.get("userId");
14719
14873
  if (!sessionToken || !email || !userId) {
14720
14874
  cleanup(() => {
14721
- resolve14({
14875
+ resolve15({
14722
14876
  success: false,
14723
14877
  error: "Invalid callback data received"
14724
14878
  });
@@ -14730,7 +14884,7 @@ async function startCallbackServer(timeoutMs) {
14730
14884
  res.writeHead(200, { "Content-Type": "text/html" });
14731
14885
  res.end(SUCCESS_HTML);
14732
14886
  cleanup(() => {
14733
- resolve14({
14887
+ resolve15({
14734
14888
  success: true,
14735
14889
  data: { sessionToken, email, userId }
14736
14890
  });
@@ -15133,7 +15287,7 @@ function sleep(ms) {
15133
15287
  if (ms <= 0) {
15134
15288
  return Promise.resolve();
15135
15289
  }
15136
- return new Promise((resolve14) => setTimeout(resolve14, ms));
15290
+ return new Promise((resolve15) => setTimeout(resolve15, ms));
15137
15291
  }
15138
15292
 
15139
15293
  // src/lib/bucket/sync.ts
@@ -16005,7 +16159,7 @@ function formatExit(name, code, signal) {
16005
16159
  return `${name} exited`;
16006
16160
  }
16007
16161
  function upgradeStandalone(targetVersion, channel) {
16008
- return new Promise((resolve14, reject) => {
16162
+ return new Promise((resolve15, reject) => {
16009
16163
  const curl = spawn2("curl", ["-fsSL", INSTALL_SCRIPT_URL], {
16010
16164
  stdio: ["ignore", "pipe", "pipe"]
16011
16165
  });
@@ -16039,7 +16193,7 @@ function upgradeStandalone(targetVersion, channel) {
16039
16193
  if (error) {
16040
16194
  reject(error);
16041
16195
  } else {
16042
- resolve14({ stdout: stdout2, stderr });
16196
+ resolve15({ stdout: stdout2, stderr });
16043
16197
  }
16044
16198
  }
16045
16199
  function tryFinalize() {
@@ -16183,6 +16337,7 @@ export {
16183
16337
  detectExistingEngine,
16184
16338
  detectMatchedCourseDrift,
16185
16339
  detectTimebackDrift,
16340
+ detectVersionRollback,
16186
16341
  discoverCustomRoutes,
16187
16342
  discoverDependencies,
16188
16343
  discoverMetricsResolver,
@@ -16229,6 +16384,7 @@ export {
16229
16384
  findPackageUpdates,
16230
16385
  findSingleBuildZip,
16231
16386
  findTemplateById,
16387
+ findVersionRollbacks,
16232
16388
  findViteConfig,
16233
16389
  formatBytes,
16234
16390
  formatConfigWithPrettier,
@@ -16329,10 +16485,12 @@ export {
16329
16485
  isGodotProject,
16330
16486
  isIgnoredByGitignore,
16331
16487
  isManifestKey,
16488
+ isManifestV2,
16332
16489
  isNonInteractive,
16333
16490
  isNotFoundError,
16334
16491
  isNudgeDue,
16335
16492
  isPluginConfigured,
16493
+ isRecord,
16336
16494
  isVitePluginInstalled,
16337
16495
  listProfiles,
16338
16496
  loadAndValidateMigrations,
@@ -16381,6 +16539,7 @@ export {
16381
16539
  promptPlatformCourseSync,
16382
16540
  queueBindingName,
16383
16541
  queueNameForDeployment,
16542
+ readBuildManifest,
16384
16543
  readEnvFile,
16385
16544
  readLocalAsset,
16386
16545
  readLocalManifest,
@@ -16410,6 +16569,7 @@ export {
16410
16569
  resolveInstalledVersion,
16411
16570
  resolveMigrationDecision,
16412
16571
  resolveSchemaStrategy,
16572
+ rollbackDisplayName,
16413
16573
  runInit,
16414
16574
  runShell,
16415
16575
  saveAuthStore,
@@ -16429,6 +16589,7 @@ export {
16429
16589
  setCliContext,
16430
16590
  setupGlobalErrorHandlers,
16431
16591
  shouldAssumeYes,
16592
+ shouldBlockVersionRollback,
16432
16593
  shouldSkipFile,
16433
16594
  skipsDeployGameDueToSecretsOnly,
16434
16595
  startCallbackServer,
@@ -414,9 +414,9 @@ var init_routes = __esm({
414
414
  // ../edge-play/src/entry/metadata.ts
415
415
  function getRuntimeMetadata() {
416
416
  return {
417
- cliVersion: true ? "0.27.1-beta.2" : "0.0.0-dev",
418
- sdkVersion: true ? "0.15.1-beta.1" : "0.0.0-dev",
419
- buildId: true ? "d545e8dcb239" : "dev-source"
417
+ cliVersion: true ? "0.27.1-beta.3" : "0.0.0-dev",
418
+ sdkVersion: true ? "0.15.1-beta.2" : "0.0.0-dev",
419
+ buildId: true ? "95a6a6d47435" : "dev-source"
420
420
  };
421
421
  }
422
422
  var init_metadata = __esm({
@@ -1,7 +1,7 @@
1
1
  {
2
- "cliVersion": "0.27.1-beta.2",
3
- "sdkVersion": "0.15.1-beta.1",
4
- "runtimeBuildId": "d545e8dcb239",
5
- "inputFingerprint": "d545e8dcb2397340ecb4aeaf21a6cfa083edd51f1fba4ad42b3b2fb6ef89ed97",
2
+ "cliVersion": "0.27.1-beta.3",
3
+ "sdkVersion": "0.15.1-beta.2",
4
+ "runtimeBuildId": "95a6a6d47435",
5
+ "inputFingerprint": "95a6a6d474353914a351765ff3ea63c9136d312f6ea6ca09ebfda295cbf16829",
6
6
  "entry": "index.js"
7
7
  }
package/dist/utils.js CHANGED
@@ -359,7 +359,7 @@ var DEFAULT_API_ROUTES_DIRECTORY = join2(SERVER_ROOT_DIRECTORY, "api");
359
359
  // ../better-auth/package.json
360
360
  var package_default = {
361
361
  name: "@playcademy/better-auth",
362
- version: "0.0.20-beta.1",
362
+ version: "0.0.20-beta.2",
363
363
  type: "module",
364
364
  exports: {
365
365
  "./server": {
@@ -2603,7 +2603,7 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as wr
2603
2603
  import { dirname as dirname4, join as join14 } from "node:path";
2604
2604
 
2605
2605
  // src/version.ts
2606
- var cliVersion = false ? "0.0.0-dev" : "0.27.1-beta.2";
2606
+ var cliVersion = false ? "0.0.0-dev" : "0.27.1-beta.3";
2607
2607
 
2608
2608
  // src/lib/build/binary-resource.ts
2609
2609
  function writeFileTree(baseDir, files) {
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var cliVersion = false ? "0.0.0-dev" : "0.27.1-beta.2";
2
+ var cliVersion = false ? "0.0.0-dev" : "0.27.1-beta.3";
3
3
  export {
4
4
  cliVersion
5
5
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playcademy",
3
- "version": "0.27.1-beta.2",
3
+ "version": "0.27.1-beta.3",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -55,7 +55,7 @@
55
55
  },
56
56
  "dependencies": {
57
57
  "@inquirer/prompts": "^7.8.6",
58
- "@playcademy/sdk": "0.15.1-beta.1",
58
+ "@playcademy/sdk": "0.15.1-beta.2",
59
59
  "chokidar": "^4.0.3",
60
60
  "colorette": "^2.0.20",
61
61
  "commander": "^14.0.1",