playcademy 0.28.1-beta.1 → 0.28.1-beta.2

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
@@ -44,7 +44,7 @@ var GAME_API_ROUTES_DIRECTORY = join2(GAME_SERVER_ROOT_DIRECTORY, "api");
44
44
  // ../better-auth/package.json
45
45
  var package_default = {
46
46
  name: "@playcademy/better-auth",
47
- version: "0.0.21-beta.1",
47
+ version: "0.0.21-beta.2",
48
48
  type: "module",
49
49
  exports: {
50
50
  "./server": {
package/dist/cli.js CHANGED
@@ -1207,7 +1207,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
1207
1207
  // ../better-auth/package.json
1208
1208
  var package_default = {
1209
1209
  name: "@playcademy/better-auth",
1210
- version: "0.0.21-beta.1",
1210
+ version: "0.0.21-beta.2",
1211
1211
  type: "module",
1212
1212
  exports: {
1213
1213
  "./server": {
@@ -3009,7 +3009,7 @@ import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as re
3009
3009
  import { join as join13 } from "node:path";
3010
3010
 
3011
3011
  // src/version.ts
3012
- var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.1";
3012
+ var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.2";
3013
3013
 
3014
3014
  // src/lib/init/database.ts
3015
3015
  var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
@@ -277,8 +277,8 @@ declare const GODOT_EXECUTABLE_PATTERNS: {
277
277
  declare const CALLBACK_PORT = 6175;
278
278
  /** Path for the OAuth callback endpoint */
279
279
  declare const CALLBACK_PATH = "/callback";
280
- /** Timeout for SSO authentication in milliseconds (30 seconds) */
281
- declare const SSO_AUTH_TIMEOUT_MS = 30000;
280
+ /** Timeout for the whole browser SSO flow (login page + provider auth + MFA) */
281
+ declare const SSO_AUTH_TIMEOUT_MS = 90000;
282
282
 
283
283
  /**
284
284
  * Path constants for CLI directories and files
package/dist/constants.js CHANGED
@@ -21,7 +21,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
21
21
  // ../better-auth/package.json
22
22
  var package_default = {
23
23
  name: "@playcademy/better-auth",
24
- version: "0.0.21-beta.1",
24
+ version: "0.0.21-beta.2",
25
25
  type: "module",
26
26
  exports: {
27
27
  "./server": {
@@ -182,7 +182,7 @@ var GODOT_EXECUTABLE_PATTERNS = {
182
182
  // src/constants/http-server.ts
183
183
  var CALLBACK_PORT = 6175;
184
184
  var CALLBACK_PATH = "/callback";
185
- var SSO_AUTH_TIMEOUT_MS = 3e4;
185
+ var SSO_AUTH_TIMEOUT_MS = 9e4;
186
186
 
187
187
  // src/constants/paths.ts
188
188
  import { homedir } from "node:os";
package/dist/db.js CHANGED
@@ -2335,7 +2335,7 @@ var GAME_API_ROUTES_DIRECTORY = join2(GAME_SERVER_ROOT_DIRECTORY, "api");
2335
2335
  // ../better-auth/package.json
2336
2336
  var package_default = {
2337
2337
  name: "@playcademy/better-auth",
2338
- version: "0.0.21-beta.1",
2338
+ version: "0.0.21-beta.2",
2339
2339
  type: "module",
2340
2340
  exports: {
2341
2341
  "./server": {
package/dist/index.d.ts CHANGED
@@ -1437,12 +1437,8 @@ interface ScaffoldResult {
1437
1437
  * Callback data received from the Playcademy server after SSO authentication
1438
1438
  */
1439
1439
  interface SsoCallbackData {
1440
- /** The session token from SSO authentication */
1441
- sessionToken: string;
1442
- /** User's email address */
1443
- email: string;
1444
- /** User's ID */
1445
- userId: string;
1440
+ /** One-time login code, exchanged at /auth/cli/exchange for an API key */
1441
+ code: string;
1446
1442
  }
1447
1443
  /**
1448
1444
  * Result from starting and running the callback server
package/dist/index.js CHANGED
@@ -2346,7 +2346,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
2346
2346
  // ../better-auth/package.json
2347
2347
  var package_default = {
2348
2348
  name: "@playcademy/better-auth",
2349
- version: "0.0.21-beta.1",
2349
+ version: "0.0.21-beta.2",
2350
2350
  type: "module",
2351
2351
  exports: {
2352
2352
  "./server": {
@@ -2500,6 +2500,7 @@ var GODOT_EXECUTABLE_PATTERNS = {
2500
2500
  // src/constants/http-server.ts
2501
2501
  var CALLBACK_PORT = 6175;
2502
2502
  var CALLBACK_PATH = "/callback";
2503
+ var SSO_AUTH_TIMEOUT_MS = 9e4;
2503
2504
 
2504
2505
  // src/constants/paths.ts
2505
2506
  import { homedir } from "node:os";
@@ -2574,6 +2575,13 @@ var CONFIG_FILE_NAMES = [
2574
2575
  "playcademy.config.mjs"
2575
2576
  ];
2576
2577
 
2578
+ // ../constants/src/auth.ts
2579
+ var DEFAULT_PERSONAL_API_KEY_PERMISSIONS = {
2580
+ games: ["read", "write", "delete"],
2581
+ users: ["read:self", "write:self"],
2582
+ dev: ["read", "write"]
2583
+ };
2584
+
2577
2585
  // ../constants/src/dashboard.ts
2578
2586
  var DASHBOARD_USER_ROLES = {
2579
2587
  ADMIN: "admin",
@@ -3148,8 +3156,8 @@ function writeBlank() {
3148
3156
  }
3149
3157
  var FG_RESET = "\x1B[39m";
3150
3158
  function nestColor(content, color2) {
3151
- const open2 = color2("").replace(FG_RESET, "");
3152
- return color2(open2 ? content.replaceAll(FG_RESET, open2) : content);
3159
+ const open3 = color2("").replace(FG_RESET, "");
3160
+ return color2(open3 ? content.replaceAll(FG_RESET, open3) : content);
3153
3161
  }
3154
3162
  function customTransform(text4) {
3155
3163
  let result = text4;
@@ -3906,9 +3914,9 @@ var Spinner = class {
3906
3914
  indent;
3907
3915
  constructor(taskIds, texts, options) {
3908
3916
  this.indent = options?.indent ?? 0;
3909
- taskIds.forEach((id, index3) => {
3917
+ taskIds.forEach((id, index4) => {
3910
3918
  this.tasks.set(id, {
3911
- text: texts[index3] || "",
3919
+ text: texts[index4] || "",
3912
3920
  status: "pending"
3913
3921
  });
3914
3922
  });
@@ -4335,9 +4343,9 @@ function buildQueueImportStatements(queueHandlers) {
4335
4343
  if (queueHandlers.length === 0) {
4336
4344
  return "// No queue handlers";
4337
4345
  }
4338
- return queueHandlers.map((handler, index3) => {
4346
+ return queueHandlers.map((handler, index4) => {
4339
4347
  const normalizedFile = handler.file.replace(/^server\//, "").replace(/\\/g, "/");
4340
- return `import queueHandler${index3} from '@game-server/${normalizedFile}'`;
4348
+ return `import queueHandler${index4} from '@game-server/${normalizedFile}'`;
4341
4349
  }).join("\n");
4342
4350
  }
4343
4351
  function buildQueueHandlerCode(queueHandlers) {
@@ -4346,7 +4354,7 @@ function buildQueueHandlerCode(queueHandlers) {
4346
4354
  }
4347
4355
  return [
4348
4356
  "const __queueHandlers = {",
4349
- ...queueHandlers.map((handler, index3) => ` '${handler.key}': queueHandler${index3},`),
4357
+ ...queueHandlers.map((handler, index4) => ` '${handler.key}': queueHandler${index4},`),
4350
4358
  "}",
4351
4359
  "",
4352
4360
  "registerQueueIngressRoute(app, __queueHandlers)",
@@ -5518,9 +5526,9 @@ function findMatchingBrace(content, openBrace) {
5518
5526
  let quote = null;
5519
5527
  let inLineComment = false;
5520
5528
  let inBlockComment = false;
5521
- for (let index3 = openBrace; index3 < content.length; index3 += 1) {
5522
- const char = content[index3];
5523
- const next = content[index3 + 1];
5529
+ for (let index4 = openBrace; index4 < content.length; index4 += 1) {
5530
+ const char = content[index4];
5531
+ const next = content[index4 + 1];
5524
5532
  if (inLineComment) {
5525
5533
  if (char === "\n") {
5526
5534
  inLineComment = false;
@@ -5528,18 +5536,18 @@ function findMatchingBrace(content, openBrace) {
5528
5536
  } else if (inBlockComment) {
5529
5537
  if (char === "*" && next === "/") {
5530
5538
  inBlockComment = false;
5531
- index3 += 1;
5539
+ index4 += 1;
5532
5540
  }
5533
5541
  } else if (quote) {
5534
- if (char === quote && !isEscapedCharacter(content, index3)) {
5542
+ if (char === quote && !isEscapedCharacter(content, index4)) {
5535
5543
  quote = null;
5536
5544
  }
5537
5545
  } else if (char === "/" && next === "/") {
5538
5546
  inLineComment = true;
5539
- index3 += 1;
5547
+ index4 += 1;
5540
5548
  } else if (char === "/" && next === "*") {
5541
5549
  inBlockComment = true;
5542
- index3 += 1;
5550
+ index4 += 1;
5543
5551
  } else if (char === "'" || char === '"' || char === "`") {
5544
5552
  quote = char;
5545
5553
  } else if (char === "{") {
@@ -5547,7 +5555,7 @@ function findMatchingBrace(content, openBrace) {
5547
5555
  } else if (char === "}") {
5548
5556
  depth -= 1;
5549
5557
  if (depth === 0) {
5550
- return index3;
5558
+ return index4;
5551
5559
  }
5552
5560
  }
5553
5561
  }
@@ -5560,9 +5568,9 @@ function isTopLevelObjectProperty(content, openBrace, keyStart) {
5560
5568
  let quote = null;
5561
5569
  let inLineComment = false;
5562
5570
  let inBlockComment = false;
5563
- for (let index3 = openBrace + 1; index3 < keyStart; index3 += 1) {
5564
- const char = content[index3];
5565
- const next = content[index3 + 1];
5571
+ for (let index4 = openBrace + 1; index4 < keyStart; index4 += 1) {
5572
+ const char = content[index4];
5573
+ const next = content[index4 + 1];
5566
5574
  if (inLineComment) {
5567
5575
  if (char === "\n") {
5568
5576
  inLineComment = false;
@@ -5570,18 +5578,18 @@ function isTopLevelObjectProperty(content, openBrace, keyStart) {
5570
5578
  } else if (inBlockComment) {
5571
5579
  if (char === "*" && next === "/") {
5572
5580
  inBlockComment = false;
5573
- index3 += 1;
5581
+ index4 += 1;
5574
5582
  }
5575
5583
  } else if (quote) {
5576
- if (char === quote && !isEscapedCharacter(content, index3)) {
5584
+ if (char === quote && !isEscapedCharacter(content, index4)) {
5577
5585
  quote = null;
5578
5586
  }
5579
5587
  } else if (char === "/" && next === "/") {
5580
5588
  inLineComment = true;
5581
- index3 += 1;
5589
+ index4 += 1;
5582
5590
  } else if (char === "/" && next === "*") {
5583
5591
  inBlockComment = true;
5584
- index3 += 1;
5592
+ index4 += 1;
5585
5593
  } else if (char === "'" || char === '"' || char === "`") {
5586
5594
  quote = char;
5587
5595
  } else if (char === "{") {
@@ -5600,9 +5608,9 @@ function isTopLevelObjectProperty(content, openBrace, keyStart) {
5600
5608
  }
5601
5609
  return !inLineComment && !inBlockComment && !quote && objectDepth === 0 && bracketDepth === 0 && parenDepth === 0;
5602
5610
  }
5603
- function isEscapedCharacter(content, index3) {
5611
+ function isEscapedCharacter(content, index4) {
5604
5612
  let backslashCount = 0;
5605
- for (let cursor2 = index3 - 1; cursor2 >= 0 && content[cursor2] === "\\"; cursor2 -= 1) {
5613
+ for (let cursor2 = index4 - 1; cursor2 >= 0 && content[cursor2] === "\\"; cursor2 -= 1) {
5606
5614
  backslashCount += 1;
5607
5615
  }
5608
5616
  return backslashCount % 2 === 1;
@@ -6382,7 +6390,7 @@ import { existsSync as existsSync10, mkdirSync as mkdirSync2, readFileSync as re
6382
6390
  import { join as join13 } from "node:path";
6383
6391
 
6384
6392
  // src/version.ts
6385
- var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.1";
6393
+ var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.2";
6386
6394
 
6387
6395
  // src/lib/init/database.ts
6388
6396
  var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
@@ -9163,12 +9171,12 @@ var MIGRATION_LEDGER_DDL = `CREATE TABLE IF NOT EXISTS ${MIGRATION_LEDGER_TABLE}
9163
9171
  // ../cloudflare/src/utils/journal.ts
9164
9172
  function findOutOfOrderTags(orderedTags, applied2) {
9165
9173
  let lastAppliedIndex = -1;
9166
- orderedTags.forEach((tag2, index3) => {
9174
+ orderedTags.forEach((tag2, index4) => {
9167
9175
  if (applied2.has(tag2)) {
9168
- lastAppliedIndex = index3;
9176
+ lastAppliedIndex = index4;
9169
9177
  }
9170
9178
  });
9171
- return orderedTags.filter((tag2, index3) => index3 < lastAppliedIndex && !applied2.has(tag2));
9179
+ return orderedTags.filter((tag2, index4) => index4 < lastAppliedIndex && !applied2.has(tag2));
9172
9180
  }
9173
9181
 
9174
9182
  // ../cloudflare/src/utils/sql.ts
@@ -9489,11 +9497,11 @@ function seedClaimedTags(seed) {
9489
9497
  if (!seed?.lastAppliedMigrationTag || !seed.journal) {
9490
9498
  return [];
9491
9499
  }
9492
- const index3 = seed.journal.findIndex((entry) => entry.tag === seed.lastAppliedMigrationTag);
9493
- if (index3 === -1) {
9500
+ const index4 = seed.journal.findIndex((entry) => entry.tag === seed.lastAppliedMigrationTag);
9501
+ if (index4 === -1) {
9494
9502
  return [];
9495
9503
  }
9496
- return seed.journal.slice(0, index3 + 1).map((entry) => entry.tag);
9504
+ return seed.journal.slice(0, index4 + 1).map((entry) => entry.tag);
9497
9505
  }
9498
9506
  async function buildPushPlan(state, options) {
9499
9507
  const adopted = isSchemaAdopted(state);
@@ -9882,8 +9890,8 @@ async function discoverRoutes(apiDir, options = {}) {
9882
9890
  const workspaceRoot = options.workspaceRoot ?? getWorkspace();
9883
9891
  const absolutePaths = files.map((file) => join27(apiDir, file));
9884
9892
  const methodsByFile = await detectExportedMethods(absolutePaths);
9885
- return files.map((file, index3) => {
9886
- const absolutePath = absolutePaths[index3];
9893
+ return files.map((file, index4) => {
9894
+ const absolutePath = absolutePaths[index4];
9887
9895
  const relativePath = relative3(workspaceRoot, absolutePath).replace(/\\/g, "/");
9888
9896
  return {
9889
9897
  path: filePathToRoutePath(file),
@@ -11583,16 +11591,16 @@ function normalizeString(path4, allowAboveRoot) {
11583
11591
  let lastSlash = -1;
11584
11592
  let dots = 0;
11585
11593
  let char = null;
11586
- for (let index3 = 0; index3 <= path4.length; ++index3) {
11587
- if (index3 < path4.length) {
11588
- char = path4[index3];
11594
+ for (let index4 = 0; index4 <= path4.length; ++index4) {
11595
+ if (index4 < path4.length) {
11596
+ char = path4[index4];
11589
11597
  } else if (char === "/") {
11590
11598
  break;
11591
11599
  } else {
11592
11600
  char = "/";
11593
11601
  }
11594
11602
  if (char === "/") {
11595
- if (lastSlash === index3 - 1 || dots === 1) ;
11603
+ if (lastSlash === index4 - 1 || dots === 1) ;
11596
11604
  else if (dots === 2) {
11597
11605
  if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
11598
11606
  if (res.length > 2) {
@@ -11604,13 +11612,13 @@ function normalizeString(path4, allowAboveRoot) {
11604
11612
  res = res.slice(0, lastSlashIndex);
11605
11613
  lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
11606
11614
  }
11607
- lastSlash = index3;
11615
+ lastSlash = index4;
11608
11616
  dots = 0;
11609
11617
  continue;
11610
11618
  } else if (res.length > 0) {
11611
11619
  res = "";
11612
11620
  lastSegmentLength = 0;
11613
- lastSlash = index3;
11621
+ lastSlash = index4;
11614
11622
  dots = 0;
11615
11623
  continue;
11616
11624
  }
@@ -11621,13 +11629,13 @@ function normalizeString(path4, allowAboveRoot) {
11621
11629
  }
11622
11630
  } else {
11623
11631
  if (res.length > 0) {
11624
- res += `/${path4.slice(lastSlash + 1, index3)}`;
11632
+ res += `/${path4.slice(lastSlash + 1, index4)}`;
11625
11633
  } else {
11626
- res = path4.slice(lastSlash + 1, index3);
11634
+ res = path4.slice(lastSlash + 1, index4);
11627
11635
  }
11628
- lastSegmentLength = index3 - lastSlash - 1;
11636
+ lastSegmentLength = index4 - lastSlash - 1;
11629
11637
  }
11630
- lastSlash = index3;
11638
+ lastSlash = index4;
11631
11639
  dots = 0;
11632
11640
  } else if (char === "." && dots !== -1) {
11633
11641
  ++dots;
@@ -12053,11 +12061,11 @@ function getDataProtocolModuleFormat(parsed) {
12053
12061
  }
12054
12062
  function extname2(url) {
12055
12063
  const pathname = url.pathname;
12056
- let index3 = pathname.length;
12057
- while (index3--) {
12058
- const code = pathname.codePointAt(index3);
12064
+ let index4 = pathname.length;
12065
+ while (index4--) {
12066
+ const code = pathname.codePointAt(index4);
12059
12067
  if (code === 47) return "";
12060
- if (code === 46) return pathname.codePointAt(index3 - 1) === 47 ? "" : pathname.slice(index3);
12068
+ if (code === 46) return pathname.codePointAt(index4 - 1) === 47 ? "" : pathname.slice(index4);
12061
12069
  }
12062
12070
  return "";
12063
12071
  }
@@ -13113,12 +13121,12 @@ function createNodeCompatPlugin(options = {}) {
13113
13121
  // src/lib/bundle/route-codegen.ts
13114
13122
  function buildRouteModuleImports(entries, alias, varPrefix) {
13115
13123
  return entries.map(
13116
- (entry, index3) => `import * as ${varPrefix}${index3} from '${alias}/${entry.importPath}'`
13124
+ (entry, index4) => `import * as ${varPrefix}${index4} from '${alias}/${entry.importPath}'`
13117
13125
  );
13118
13126
  }
13119
13127
  function buildRouteModuleArrayItems(entries, varPrefix) {
13120
13128
  return entries.map(
13121
- (entry, index3) => ` { path: ${JSON.stringify(entry.path)}, module: ${varPrefix}${index3} },`
13129
+ (entry, index4) => ` { path: ${JSON.stringify(entry.path)}, module: ${varPrefix}${index4} },`
13122
13130
  );
13123
13131
  }
13124
13132
 
@@ -15968,10 +15976,10 @@ var ZodObject = class _ZodObject extends ZodType {
15968
15976
  // }) as any;
15969
15977
  // return merged;
15970
15978
  // }
15971
- catchall(index3) {
15979
+ catchall(index4) {
15972
15980
  return new _ZodObject({
15973
15981
  ...this._def,
15974
- catchall: index3
15982
+ catchall: index4
15975
15983
  });
15976
15984
  }
15977
15985
  pick(mask) {
@@ -16289,9 +16297,9 @@ function mergeValues(a, b) {
16289
16297
  return { valid: false };
16290
16298
  }
16291
16299
  const newArray = [];
16292
- for (let index3 = 0; index3 < a.length; index3++) {
16293
- const itemA = a[index3];
16294
- const itemB = b[index3];
16300
+ for (let index4 = 0; index4 < a.length; index4++) {
16301
+ const itemA = a[index4];
16302
+ const itemB = b[index4];
16295
16303
  const sharedValue = mergeValues(itemA, itemB);
16296
16304
  if (!sharedValue.valid) {
16297
16305
  return { valid: false };
@@ -16497,10 +16505,10 @@ var ZodMap = class extends ZodType {
16497
16505
  }
16498
16506
  const keyType = this._def.keyType;
16499
16507
  const valueType = this._def.valueType;
16500
- const pairs = [...ctx.data.entries()].map(([key, value], index3) => {
16508
+ const pairs = [...ctx.data.entries()].map(([key, value], index4) => {
16501
16509
  return {
16502
- key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index3, "key"])),
16503
- value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index3, "value"]))
16510
+ key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index4, "key"])),
16511
+ value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index4, "value"]))
16504
16512
  };
16505
16513
  });
16506
16514
  if (ctx.common.async) {
@@ -20895,8 +20903,8 @@ function diffCreated(base, target) {
20895
20903
  }
20896
20904
  }
20897
20905
  }
20898
- for (const [indexKey, index3] of Object.entries(table.indexes ?? {})) {
20899
- const name = index3.name ?? indexKey;
20906
+ for (const [indexKey, index4] of Object.entries(table.indexes ?? {})) {
20907
+ const name = index4.name ?? indexKey;
20900
20908
  if (!counterpart?.indexes?.[indexKey] && name) {
20901
20909
  createsIndexes.push(name);
20902
20910
  }
@@ -23857,7 +23865,7 @@ import { and, eq } from "drizzle-orm";
23857
23865
  import { relations } from "drizzle-orm";
23858
23866
  import {
23859
23867
  boolean as boolean2,
23860
- index,
23868
+ index as index2,
23861
23869
  integer,
23862
23870
  jsonb,
23863
23871
  pgEnum as pgEnum2,
@@ -23870,7 +23878,7 @@ import {
23870
23878
  } from "drizzle-orm/pg-core";
23871
23879
 
23872
23880
  // ../data/src/domains/user/table.ts
23873
- import { boolean, pgEnum, pgTable, text, timestamp, uniqueIndex } from "drizzle-orm/pg-core";
23881
+ import { boolean, index, pgEnum, pgTable, text, timestamp, uniqueIndex } from "drizzle-orm/pg-core";
23874
23882
  var userRoleEnum = pgEnum("user_role", ["admin", "player", "developer", "teacher"]);
23875
23883
  var developerStatusEnum = pgEnum("developer_status", ["none", "pending", "approved"]);
23876
23884
  var users = pgTable("user", {
@@ -23948,24 +23956,30 @@ var sessions = pgTable("session", {
23948
23956
  withTimezone: true
23949
23957
  }).notNull()
23950
23958
  });
23951
- var verification = pgTable("verification", {
23952
- id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
23953
- identifier: text("identifier").notNull(),
23954
- // Typically email
23955
- value: text("value").notNull(),
23956
- expiresAt: timestamp("expires_at", {
23957
- mode: "date",
23958
- withTimezone: true
23959
- }).notNull(),
23960
- createdAt: timestamp("created_at", {
23961
- mode: "date",
23962
- withTimezone: true
23963
- }).notNull(),
23964
- updatedAt: timestamp("updated_at", {
23965
- mode: "date",
23966
- withTimezone: true
23967
- }).notNull()
23968
- });
23959
+ var verification = pgTable(
23960
+ "verification",
23961
+ {
23962
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
23963
+ identifier: text("identifier").notNull(),
23964
+ // email, or a namespaced token key
23965
+ value: text("value").notNull(),
23966
+ expiresAt: timestamp("expires_at", {
23967
+ mode: "date",
23968
+ withTimezone: true
23969
+ }).notNull(),
23970
+ createdAt: timestamp("created_at", {
23971
+ mode: "date",
23972
+ withTimezone: true
23973
+ }).notNull(),
23974
+ updatedAt: timestamp("updated_at", {
23975
+ mode: "date",
23976
+ withTimezone: true
23977
+ }).notNull()
23978
+ },
23979
+ // Every lookup (better-auth's own token verification, and the CLI login-code
23980
+ // redemption) keys on identifier; without this it degrades to a table scan.
23981
+ (table) => [index("verification_identifier_idx").on(table.identifier)]
23982
+ );
23969
23983
 
23970
23984
  // ../data/src/domains/game/table.ts
23971
23985
  var gamePlatformEnum = pgEnum2("game_platform", ["web", "godot", "unity"]);
@@ -24085,7 +24099,7 @@ var gameDeployments = pgTable2(
24085
24099
  },
24086
24100
  // Every per-request lookup (active deployment, restore points) filters
24087
24101
  // by game and target over this append-only table
24088
- (table) => [index("game_deployments_game_target_idx").on(table.gameId, table.target)]
24102
+ (table) => [index2("game_deployments_game_target_idx").on(table.gameId, table.target)]
24089
24103
  );
24090
24104
  var gameDeployJobs = pgTable2(
24091
24105
  "game_deploy_jobs",
@@ -24133,7 +24147,7 @@ var gameDeployEvents = pgTable2(
24133
24147
  createdAt: timestamp2("created_at", { mode: "date", withTimezone: true }).notNull().defaultNow()
24134
24148
  },
24135
24149
  // History reads are per game, newest first.
24136
- (table) => [index("game_deploy_events_game_idx").on(table.gameId, table.createdAt)]
24150
+ (table) => [index2("game_deploy_events_game_idx").on(table.gameId, table.createdAt)]
24137
24151
  );
24138
24152
  var gameDeploymentState = pgTable2("game_deployment_state", {
24139
24153
  id: uuid("id").primaryKey().defaultRandom(),
@@ -24210,7 +24224,7 @@ import { sql as sql2 } from "drizzle-orm";
24210
24224
  import { sql } from "drizzle-orm";
24211
24225
  import {
24212
24226
  doublePrecision,
24213
- index as index2,
24227
+ index as index3,
24214
24228
  integer as integer2,
24215
24229
  pgEnum as pgEnum3,
24216
24230
  pgTable as pgTable3,
@@ -24293,7 +24307,7 @@ var gameTimebackMetricDiscrepancyVerifications = pgTable3(
24293
24307
  table.studentId,
24294
24308
  table.runId
24295
24309
  ),
24296
- index2("game_timeback_metric_discrepancy_verifications_course_idx").on(
24310
+ index3("game_timeback_metric_discrepancy_verifications_course_idx").on(
24297
24311
  table.gameId,
24298
24312
  table.courseId,
24299
24313
  table.verifiedAt
@@ -25593,8 +25607,8 @@ function displayMigrateDiff(plan) {
25593
25607
  1
25594
25608
  );
25595
25609
  logger.newLine();
25596
- plan.pendingTags.forEach((tag2, index3) => {
25597
- logger.data(`${index3 + 1}`, tag2, 1);
25610
+ plan.pendingTags.forEach((tag2, index4) => {
25611
+ logger.data(`${index4 + 1}`, tag2, 1);
25598
25612
  });
25599
25613
  logger.newLine();
25600
25614
  return;
@@ -26219,6 +26233,27 @@ async function executeSeedFile(seedFilePath, mf, envSecrets = {}) {
26219
26233
  logger.newLine();
26220
26234
  }
26221
26235
 
26236
+ // src/lib/auth/exchange.ts
26237
+ var EXCHANGE_TIMEOUT_MS = 15e3;
26238
+ async function exchangeLoginCode(baseUrl, code, name) {
26239
+ const response = await fetch(`${baseUrl}/auth/cli/exchange`, {
26240
+ method: "POST",
26241
+ headers: { "Content-Type": "application/json" },
26242
+ body: JSON.stringify({ code, name }),
26243
+ signal: AbortSignal.timeout(EXCHANGE_TIMEOUT_MS)
26244
+ });
26245
+ const body = await response.json().catch(() => null);
26246
+ if (!response.ok || !body?.apiKey || !body.userId || !body.email) {
26247
+ throw new Error(body?.error || `Login code exchange failed (HTTP ${response.status})`);
26248
+ }
26249
+ return { apiKey: body.apiKey, userId: body.userId, email: body.email };
26250
+ }
26251
+
26252
+ // src/lib/auth/login-flow.ts
26253
+ import { userInfo } from "os";
26254
+ import { bold as bold12, whiteBright } from "colorette";
26255
+ import open from "open";
26256
+
26222
26257
  // src/lib/auth/http-server/server.ts
26223
26258
  import { createServer as createServer2 } from "node:http";
26224
26259
 
@@ -26349,10 +26384,27 @@ function getErrorHtml(error) {
26349
26384
  }
26350
26385
 
26351
26386
  // src/lib/auth/http-server/server.ts
26352
- async function startCallbackServer(timeoutMs) {
26353
- return new Promise((resolve18) => {
26387
+ function parseCallbackRequest(url, expectedState) {
26388
+ if (url.searchParams.get("state") !== expectedState) {
26389
+ return { success: false, error: "The response does not belong to this login attempt" };
26390
+ }
26391
+ const code = url.searchParams.get("code");
26392
+ if (!code) {
26393
+ return { success: false, error: "Invalid callback data received" };
26394
+ }
26395
+ return { success: true, data: { code } };
26396
+ }
26397
+ function startCallbackServer(timeoutMs, expectedState) {
26398
+ let bound;
26399
+ let bindFailed;
26400
+ const listening = new Promise((res, rej) => {
26401
+ bound = res;
26402
+ bindFailed = rej;
26403
+ });
26404
+ const result = new Promise((resolve18) => {
26354
26405
  let server = null;
26355
26406
  let timeoutId = null;
26407
+ let didBind = false;
26356
26408
  function cleanup(callback) {
26357
26409
  if (timeoutId) {
26358
26410
  clearTimeout(timeoutId);
@@ -26377,16 +26429,8 @@ async function startCallbackServer(timeoutMs) {
26377
26429
  server = createServer2((req, res) => {
26378
26430
  const url = new URL(req.url, `http://localhost:${CALLBACK_PORT}`);
26379
26431
  if (url.pathname === CALLBACK_PATH) {
26380
- const sessionToken = url.searchParams.get("sessionToken");
26381
- const email = url.searchParams.get("email");
26382
- const userId = url.searchParams.get("userId");
26383
- if (!sessionToken || !email || !userId) {
26384
- cleanup(() => {
26385
- resolve18({
26386
- success: false,
26387
- error: "Invalid callback data received"
26388
- });
26389
- });
26432
+ const parsed = parseCallbackRequest(url, expectedState);
26433
+ if (!parsed.success) {
26390
26434
  res.writeHead(400, { "Content-Type": "text/html" });
26391
26435
  res.end(getErrorHtml("Invalid authentication data"));
26392
26436
  return;
@@ -26394,23 +26438,164 @@ async function startCallbackServer(timeoutMs) {
26394
26438
  res.writeHead(200, { "Content-Type": "text/html" });
26395
26439
  res.end(SUCCESS_HTML);
26396
26440
  cleanup(() => {
26397
- resolve18({
26398
- success: true,
26399
- data: { sessionToken, email, userId }
26400
- });
26441
+ resolve18(parsed);
26401
26442
  });
26402
26443
  return;
26403
26444
  }
26404
26445
  res.writeHead(404, { "Content-Type": "text/plain" });
26405
26446
  res.end("Not Found");
26406
26447
  });
26448
+ server.on("listening", () => {
26449
+ didBind = true;
26450
+ bound();
26451
+ });
26452
+ server.on("error", (error) => {
26453
+ const reason = error.code === "EADDRINUSE" ? `Port ${CALLBACK_PORT} is already in use \u2014 is another \`playcademy login\` running?` : errorMessage(error);
26454
+ const message2 = `Could not start the login listener: ${reason}`;
26455
+ if (!didBind) {
26456
+ bindFailed(new Error(message2));
26457
+ }
26458
+ cleanup(() => {
26459
+ resolve18({ success: false, error: message2 });
26460
+ });
26461
+ });
26407
26462
  server.listen(CALLBACK_PORT);
26408
26463
  });
26464
+ return { listening, result };
26409
26465
  }
26410
26466
  function getCallbackUrl() {
26411
26467
  return `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
26412
26468
  }
26413
26469
 
26470
+ // src/lib/auth/login-flow.ts
26471
+ var STATE_LENGTH = 22;
26472
+ function cliKeyName() {
26473
+ return userInfo().username.substring(0, 32);
26474
+ }
26475
+ async function runEmailPasswordLogin(environment, profileName, email, userPassword) {
26476
+ try {
26477
+ const client = await createClient();
26478
+ const loginResult = await runStep(
26479
+ "Logging in with email/password",
26480
+ async () => {
26481
+ const result = await client.auth.login({ email, password: userPassword });
26482
+ if (!result.success) {
26483
+ throw new Error(result.error || "Login failed");
26484
+ }
26485
+ return result;
26486
+ },
26487
+ () => "Successfully authenticated"
26488
+ );
26489
+ const apiKeyResult = await runStep(
26490
+ "Creating API key for CLI usage",
26491
+ () => client.auth.apiKeys.create({
26492
+ name: cliKeyName(),
26493
+ expiresIn: null,
26494
+ // No expiration
26495
+ permissions: DEFAULT_PERSONAL_API_KEY_PERMISSIONS
26496
+ }),
26497
+ "API key created successfully"
26498
+ );
26499
+ const authProfile = {
26500
+ token: apiKeyResult.apiKey,
26501
+ tokenType: "apiKey",
26502
+ userId: loginResult.user.id,
26503
+ email: loginResult.user.email
26504
+ };
26505
+ logger.admonition("warning", "Your API Key", [apiKeyResult.apiKey]);
26506
+ logger.warn("Save this key securely - it will not be shown again!", 1);
26507
+ logger.newLine();
26508
+ await runStep(
26509
+ `Saving credentials to profile "${profileName}"`,
26510
+ () => saveProfile(environment, profileName, authProfile),
26511
+ "Credentials saved successfully"
26512
+ );
26513
+ logger.admonition("tip", "Logged In Successfully!", [
26514
+ `Email: ${authProfile.email}`,
26515
+ `Environment: ${environment}`,
26516
+ ...profileName !== "default" ? [`Profile: ${profileName}`] : [],
26517
+ ...profileName !== "default" ? [`Use \`--profile ${profileName}\` with commands to use this profile`] : [],
26518
+ "",
26519
+ "Learn more: <<https://docs.playcademy.net/platform/cli/authentication>>"
26520
+ ]);
26521
+ } catch (error) {
26522
+ logAndExit(error, { prefix: "Authentication failed" });
26523
+ }
26524
+ }
26525
+ async function runSsoLogin(environment, profileName) {
26526
+ try {
26527
+ const state = generateSecureRandomStringSync(STATE_LENGTH);
26528
+ const server = startCallbackServer(SSO_AUTH_TIMEOUT_MS, state);
26529
+ await server.listening;
26530
+ const baseUrl = getBaseUrl();
26531
+ const callbackUrl = getCallbackUrl();
26532
+ const authUrl = `${baseUrl}/auth/cli?callback=${encodeURIComponent(callbackUrl)}&state=${state}`;
26533
+ await open(authUrl);
26534
+ logger.admonition("info", "Waiting for Authentication", [
26535
+ "Please complete authentication in your browser..."
26536
+ ]);
26537
+ const result = await server.result;
26538
+ if (!result.success || !result.data) {
26539
+ logger.newLine();
26540
+ logger.error(`Authentication failed: ${result.error || "Unknown error"}`);
26541
+ logger.newLine();
26542
+ process.exit(1);
26543
+ }
26544
+ const code = result.data.code;
26545
+ const exchange = await runStep(
26546
+ "Creating API key for CLI usage",
26547
+ () => exchangeLoginCode(baseUrl, code, cliKeyName()),
26548
+ "API key created successfully"
26549
+ );
26550
+ const authProfile = {
26551
+ token: exchange.apiKey,
26552
+ tokenType: "apiKey",
26553
+ userId: exchange.userId,
26554
+ email: exchange.email
26555
+ };
26556
+ logger.admonition("warning", "Your API Key", [
26557
+ "Save this key securely - it will not be shown again!",
26558
+ "",
26559
+ whiteBright(bold12(exchange.apiKey))
26560
+ ]);
26561
+ await runStep(
26562
+ `Saving credentials to profile "${profileName}"`,
26563
+ () => saveProfile(environment, profileName, authProfile),
26564
+ "Credentials saved successfully",
26565
+ { silent: true }
26566
+ );
26567
+ logger.success(`Logged in to ${environment} as ${authProfile.email}`);
26568
+ logger.newLine();
26569
+ } catch (error) {
26570
+ logAndExit(error, { prefix: "SSO authentication failed" });
26571
+ }
26572
+ }
26573
+ async function promptForEmail() {
26574
+ return input({
26575
+ message: "Email:",
26576
+ nonInteractiveHint: "Pass --email or authenticate with PLAYCADEMY_API_TOKEN.",
26577
+ validate: (value) => {
26578
+ if (!value || !value.includes("@")) {
26579
+ return "Please enter a valid email address";
26580
+ }
26581
+ return true;
26582
+ }
26583
+ });
26584
+ }
26585
+ async function promptForPassword() {
26586
+ return password({
26587
+ message: "Password:",
26588
+ mask: "*",
26589
+ nonInteractiveHint: "Pass --password or authenticate with PLAYCADEMY_API_TOKEN.",
26590
+ validate: (value) => {
26591
+ if (!value) {
26592
+ return "Password is required";
26593
+ }
26594
+ return true;
26595
+ }
26596
+ });
26597
+ }
26598
+
26414
26599
  // src/lib/bucket/collect.ts
26415
26600
  import { readdirSync as readdirSync6, statSync as statSync4 } from "fs";
26416
26601
  import { join as join55, relative as relative8, sep as sep4 } from "path";
@@ -26557,7 +26742,7 @@ function buildManifest(hashedFiles) {
26557
26742
  }
26558
26743
 
26559
26744
  // src/lib/bucket/migrate.ts
26560
- import { bold as bold12, cyan as cyan7 } from "colorette";
26745
+ import { bold as bold13, cyan as cyan7 } from "colorette";
26561
26746
  var SAMPLE_LIMIT = 10;
26562
26747
  async function resolveMigrationDecision({
26563
26748
  shadowedOriginals,
@@ -26586,7 +26771,7 @@ async function resolveMigrationDecision({
26586
26771
  }
26587
26772
  logger.admonition("info", "Migrating your bucket to versioned assets", [
26588
26773
  `Versioned filenames make each URL immutable to facilitate better caching.`,
26589
- `Found ${bold12(`${count} ${noun}`)} using the previous layout, listed below.`
26774
+ `Found ${bold13(`${count} ${noun}`)} using the previous layout, listed below.`
26590
26775
  ]);
26591
26776
  const sample = shadowedOriginals.slice(0, SAMPLE_LIMIT);
26592
26777
  logger.table(sample.map((o) => ({ Key: o.key, Size: formatBytes(o.size) })));
@@ -26633,15 +26818,15 @@ async function resolveMigrationDecision({
26633
26818
  message: "Select the files to remove (unchecked files are kept):",
26634
26819
  choices: shadowedOriginals.map((o) => ({
26635
26820
  value: o.key,
26636
- name: `${o.key} ${bold12(`(${formatBytes(o.size)})`)}`
26821
+ name: `${o.key} ${bold13(`(${formatBytes(o.size)})`)}`
26637
26822
  })),
26638
- instructions: ` ${bold12("(")}${cyan7("space")}${bold12(" to toggle, ")}${cyan7("enter")}${bold12(" to confirm)")}`,
26823
+ instructions: ` ${bold13("(")}${cyan7("space")}${bold13(" to toggle, ")}${cyan7("enter")}${bold13(" to confirm)")}`,
26639
26824
  nonInteractiveHint: NON_INTERACTIVE_HINTS.MIGRATE_MODE
26640
26825
  });
26641
26826
  }
26642
26827
 
26643
26828
  // src/lib/bucket/output.ts
26644
- import { bold as bold13, dim as dim12, yellowBright as yellowBright2 } from "colorette";
26829
+ import { bold as bold14, dim as dim12, yellowBright as yellowBright2 } from "colorette";
26645
26830
  function collectSyncFiles(directory) {
26646
26831
  const gitignorePatterns = loadGitignorePatterns(directory);
26647
26832
  return collectFiles(directory, directory, gitignorePatterns);
@@ -26667,7 +26852,7 @@ function outputDryRunResults(plan, json) {
26667
26852
  logger.newLine();
26668
26853
  return;
26669
26854
  }
26670
- logger.raw(`${bold13(yellowBright2("\u2726"))} ${bold13("Dry run")} ${dim12("(no changes will be made)")}`);
26855
+ logger.raw(`${bold14(yellowBright2("\u2726"))} ${bold14("Dry run")} ${dim12("(no changes will be made)")}`);
26671
26856
  logger.newLine();
26672
26857
  if (plan.toUpload.length > 0) {
26673
26858
  const count = plan.toUpload.length;
@@ -27001,7 +27186,7 @@ function buildCollectorUrl(workerId, endpoint, token) {
27001
27186
  }
27002
27187
 
27003
27188
  // src/lib/logs/display.ts
27004
- import { blue as blue3, bold as bold14, cyan as cyan8, dim as dim14, gray as gray2, green as green9, magenta as magenta3, red as red6, yellow as yellow7 } from "colorette";
27189
+ import { blue as blue3, bold as bold15, cyan as cyan8, dim as dim14, gray as gray2, green as green9, magenta as magenta3, red as red6, yellow as yellow7 } from "colorette";
27005
27190
  var LEVEL_COLORS = {
27006
27191
  log: gray2,
27007
27192
  info: blue3,
@@ -27059,7 +27244,7 @@ function formatStatus(status) {
27059
27244
  } else if (status >= 200) {
27060
27245
  colorFn = green9;
27061
27246
  }
27062
- const boldCode = colorFn(bold14(String(status)));
27247
+ const boldCode = colorFn(bold15(String(status)));
27063
27248
  return text4 ? `${boldCode} ${colorFn(text4)}` : boldCode;
27064
27249
  }
27065
27250
  function stripLogPrefix(message2) {
@@ -27095,7 +27280,7 @@ function displayLogEntry(entry) {
27095
27280
  const queueMatch = path4.match(/^\/__playcademy\/queue\/(.+)$/);
27096
27281
  if (queueMatch) {
27097
27282
  const queueKey = decodeURIComponent(queueMatch[1]);
27098
- const label = magenta3(bold14("QUEUE"));
27283
+ const label = magenta3(bold15("QUEUE"));
27099
27284
  let status = outcomeColor(entry.outcome);
27100
27285
  if (entry.outcome === "ok") {
27101
27286
  status = green9("processed");
@@ -27104,7 +27289,7 @@ function displayLogEntry(entry) {
27104
27289
  }
27105
27290
  logger.raw(`${time} ${label} ${queueKey} ${status}`);
27106
27291
  } else {
27107
- const method = cyan8(bold14(entry.request.method));
27292
+ const method = cyan8(bold15(entry.request.method));
27108
27293
  const status = entry.response?.status;
27109
27294
  let statusPart = "";
27110
27295
  if (status) {
@@ -27120,12 +27305,12 @@ function displayLogEntry(entry) {
27120
27305
  }
27121
27306
  for (const log2 of entry.logs) {
27122
27307
  const levelColor = LEVEL_COLORS[log2.level] ?? gray2;
27123
- const level = levelColor(bold14(log2.level.toUpperCase()));
27308
+ const level = levelColor(bold15(log2.level.toUpperCase()));
27124
27309
  const message2 = log2.message.map(formatValue2).join(" ");
27125
27310
  logger.raw(`${time} ${level} ${message2}`);
27126
27311
  }
27127
27312
  for (const exception of entry.exceptions) {
27128
- const level = red6(bold14("ERROR"));
27313
+ const level = red6(bold15("ERROR"));
27129
27314
  logger.raw(`${time} ${level} ${exception.name}: ${exception.message}`);
27130
27315
  }
27131
27316
  }
@@ -27559,7 +27744,7 @@ function isRealCalendarDate(year2, month, day2) {
27559
27744
  }
27560
27745
 
27561
27746
  // src/lib/timeback/display.ts
27562
- import { bold as bold15, greenBright as greenBright2, redBright as redBright3 } from "colorette";
27747
+ import { bold as bold16, greenBright as greenBright2, redBright as redBright3 } from "colorette";
27563
27748
  function displayIntegrationDetails(integration) {
27564
27749
  logger.highlight("Verified Course");
27565
27750
  logger.newLine();
@@ -27596,9 +27781,9 @@ function displayIntegrationList(integrations, statusByCourseId, options) {
27596
27781
  if (showStatusColumn) {
27597
27782
  if (options?.staticLabel) {
27598
27783
  const coloredLabel = options.staticLabelColor ? options.staticLabelColor(options.staticLabel) : greenBright2(options.staticLabel);
27599
- statusText = bold15(coloredLabel);
27784
+ statusText = bold16(coloredLabel);
27600
27785
  } else if (statusByCourseId && integration.courseId in statusByCourseId) {
27601
- statusText = statusByCourseId[integration.courseId] ? bold15(greenBright2(successLabel)) : bold15(redBright3(failureLabel));
27786
+ statusText = statusByCourseId[integration.courseId] ? bold16(greenBright2(successLabel)) : bold16(redBright3(failureLabel));
27602
27787
  }
27603
27788
  }
27604
27789
  const row = {
@@ -27631,7 +27816,7 @@ function displayCleanupWarning(integrations, gameName, logger2) {
27631
27816
  }
27632
27817
 
27633
27818
  // src/lib/timeback/setup.ts
27634
- import { bold as bold16 } from "colorette";
27819
+ import { bold as bold17 } from "colorette";
27635
27820
  function displaySetupDryRun(derivedRequest, env, logger2) {
27636
27821
  logger2.highlight("TimeBack Setup [DRY RUN]");
27637
27822
  logger2.newLine();
@@ -27660,7 +27845,7 @@ function displaySetupDryRun(derivedRequest, env, logger2) {
27660
27845
  logger2.admonition("tip", "Ready for setup", [
27661
27846
  "Your Timeback configuration has been validated!",
27662
27847
  "",
27663
- `Run without \`--dry-run\` to create ${bold16(`${derivedRequest.courses.length} course(s)`)} in ${bold16(env || "staging")}`
27848
+ `Run without \`--dry-run\` to create ${bold17(`${derivedRequest.courses.length} course(s)`)} in ${bold17(env || "staging")}`
27664
27849
  ]);
27665
27850
  }
27666
27851
 
@@ -28016,7 +28201,7 @@ function getInstallMethod() {
28016
28201
  }
28017
28202
 
28018
28203
  // src/lib/upgrade/guards.ts
28019
- import { bold as bold17 } from "colorette";
28204
+ import { bold as bold18 } from "colorette";
28020
28205
 
28021
28206
  // src/lib/upgrade/constants.ts
28022
28207
  var INSTALL_SCRIPT_URL = "https://playcademy.net/cli";
@@ -28064,7 +28249,7 @@ function handleNonStandaloneInstall(installMethod) {
28064
28249
  };
28065
28250
  const uninstallCmd = uninstallCommands[installMethod];
28066
28251
  logger.admonition("warning", "Legacy Install Detected", [
28067
- `The CLI was installed via ${bold17(installMethod)}, which is no longer supported.`,
28252
+ `The CLI was installed via ${bold18(installMethod)}, which is no longer supported.`,
28068
28253
  "",
28069
28254
  "Uninstall it first (it would shadow the standalone binary):",
28070
28255
  "",
@@ -28076,7 +28261,7 @@ function handleNonStandaloneInstall(installMethod) {
28076
28261
  }
28077
28262
 
28078
28263
  // src/lib/upgrade/perform.ts
28079
- import { bold as bold18, dim as dim15, green as green10, red as red7, yellow as yellow8 } from "colorette";
28264
+ import { bold as bold19, dim as dim15, green as green10, red as red7, yellow as yellow8 } from "colorette";
28080
28265
 
28081
28266
  // src/lib/upgrade/standalone.ts
28082
28267
  import { spawn as spawn2 } from "node:child_process";
@@ -28227,7 +28412,7 @@ function verifyInstalledBinary(expectedVersion) {
28227
28412
  // src/lib/upgrade/windows.ts
28228
28413
  import { createHash as createHash6 } from "node:crypto";
28229
28414
  import { existsSync as existsSync39 } from "node:fs";
28230
- import { copyFile, mkdir as mkdir9, open, rename, rm as rm3 } from "node:fs/promises";
28415
+ import { copyFile, mkdir as mkdir9, open as open2, rename, rm as rm3 } from "node:fs/promises";
28231
28416
  import { homedir as homedir3 } from "node:os";
28232
28417
  import { basename as basename5, dirname as dirname9, join as join58 } from "node:path";
28233
28418
  var COMPANION_TOOLS = ["workerd", "esbuild"];
@@ -28282,7 +28467,7 @@ async function downloadVerified(url, expected, download) {
28282
28467
  throw new Error(`Download failed (HTTP ${response.status}): ${url}`);
28283
28468
  }
28284
28469
  const hash = createHash6("sha256");
28285
- const handle = await open(download, "w");
28470
+ const handle = await open2(download, "w");
28286
28471
  try {
28287
28472
  for await (const chunk of response.body) {
28288
28473
  hash.update(chunk);
@@ -28359,13 +28544,13 @@ async function swapInPlace(dest, download) {
28359
28544
  function printUpgradeHeader(currentVersion, desiredVersion, isDowngrade) {
28360
28545
  const targetColor = isDowngrade ? yellow8 : green10;
28361
28546
  console.log(
28362
- ` ${bold18("Playcademy CLI")} ${bold18("(")}${red7(currentVersion)} \u2192 ${targetColor(desiredVersion)}${bold18(")")}`
28547
+ ` ${bold19("Playcademy CLI")} ${bold19("(")}${red7(currentVersion)} \u2192 ${targetColor(desiredVersion)}${bold19(")")}`
28363
28548
  );
28364
28549
  logger.newLine();
28365
28550
  }
28366
28551
  function reportUpToDate(desiredVersion) {
28367
28552
  console.log(
28368
- ` ${green10("\u2714")} ${bold18("Playcademy CLI")} ${dim15(`${desiredVersion} is already up to date`)}`
28553
+ ` ${green10("\u2714")} ${bold19("Playcademy CLI")} ${dim15(`${desiredVersion} is already up to date`)}`
28369
28554
  );
28370
28555
  logger.newLine();
28371
28556
  }
@@ -28374,7 +28559,7 @@ async function performUpgrade(resolved) {
28374
28559
  const isDowngrade = resolved.direction > 0;
28375
28560
  printUpgradeHeader(currentVersion, desiredVersion, isDowngrade);
28376
28561
  const shouldUpgrade = await confirm({
28377
- message: `Download and install ${bold18(desiredVersion)}?`,
28562
+ message: `Download and install ${bold19(desiredVersion)}?`,
28378
28563
  default: true,
28379
28564
  nonInteractiveHint: "Pass --yes to confirm the upgrade."
28380
28565
  });
@@ -28382,7 +28567,7 @@ async function performUpgrade(resolved) {
28382
28567
  logger.newLine();
28383
28568
  process.exit(0);
28384
28569
  }
28385
- const doneLabel = isDowngrade ? `Installed ${bold18(desiredVersion)}` : `Upgraded to ${bold18(desiredVersion)}`;
28570
+ const doneLabel = isDowngrade ? `Installed ${bold19(desiredVersion)}` : `Upgraded to ${bold19(desiredVersion)}`;
28386
28571
  await runStep(
28387
28572
  "Downloading and installing...",
28388
28573
  async () => {
@@ -28603,6 +28788,7 @@ export {
28603
28788
  ensurePlaycademyTypes,
28604
28789
  ensureRootGitignore,
28605
28790
  entrySearchText,
28791
+ exchangeLoginCode,
28606
28792
  executeSeedFile,
28607
28793
  executeUpdates,
28608
28794
  exitAfterStdoutDrain,
@@ -28775,6 +28961,7 @@ export {
28775
28961
  outOfOrderLines,
28776
28962
  outputDryRunResults,
28777
28963
  outputSyncResults,
28964
+ parseCallbackRequest,
28778
28965
  parseChannelFlag,
28779
28966
  parseCompatibilityManifest,
28780
28967
  parseHistoryBody,
@@ -28798,10 +28985,12 @@ export {
28798
28985
  promptForAuthStrategies,
28799
28986
  promptForCustomRoutes,
28800
28987
  promptForDatabase,
28988
+ promptForEmail,
28801
28989
  promptForEngine,
28802
28990
  promptForFramework,
28803
28991
  promptForIntegrations,
28804
28992
  promptForMissingConfig,
28993
+ promptForPassword,
28805
28994
  promptForProjectDirectory,
28806
28995
  promptForProjectInfo,
28807
28996
  promptForTemplate,
@@ -28865,8 +29054,10 @@ export {
28865
29054
  resolveUpgrade,
28866
29055
  restoreUnsupportedLines,
28867
29056
  rollbackDisplayName,
29057
+ runEmailPasswordLogin,
28868
29058
  runInit,
28869
29059
  runShell,
29060
+ runSsoLogin,
28870
29061
  saveAuthStore,
28871
29062
  saveDeployedGame,
28872
29063
  saveDeploymentState,
@@ -1,7 +1,7 @@
1
1
  {
2
- "cliVersion": "0.28.1-beta.1",
3
- "sdkVersion": "0.16.1-beta.1",
4
- "runtimeBuildId": "e927c5aa07bd",
5
- "inputFingerprint": "e927c5aa07bdd6d27f0d41ef862380da6c5d5c9b74b8a4f398aa7a4012559577",
2
+ "cliVersion": "0.28.1-beta.2",
3
+ "sdkVersion": "0.16.1-beta.2",
4
+ "runtimeBuildId": "ae26f3f7d729",
5
+ "inputFingerprint": "ae26f3f7d7295446ac2eeefeefd3796000b0ff85798ee067d55becd93088a976",
6
6
  "entry": "index.js"
7
7
  }
@@ -6510,9 +6510,9 @@ var init_list = __esm({
6510
6510
  // ../edge-play/src/game/lib/metadata.ts
6511
6511
  function getRuntimeMetadata() {
6512
6512
  return {
6513
- cliVersion: true ? "0.28.1-beta.1" : "0.0.0-dev",
6514
- sdkVersion: true ? "0.16.1-beta.1" : "0.0.0-dev",
6515
- buildId: true ? "e927c5aa07bd" : "dev-source"
6513
+ cliVersion: true ? "0.28.1-beta.2" : "0.0.0-dev",
6514
+ sdkVersion: true ? "0.16.1-beta.2" : "0.0.0-dev",
6515
+ buildId: true ? "ae26f3f7d729" : "dev-source"
6516
6516
  };
6517
6517
  }
6518
6518
  var init_metadata = __esm({
@@ -1,7 +1,7 @@
1
1
  {
2
- "cliVersion": "0.28.1-beta.1",
3
- "sdkVersion": "0.16.1-beta.1",
4
- "runtimeBuildId": "e927c5aa07bd",
5
- "inputFingerprint": "e927c5aa07bdd6d27f0d41ef862380da6c5d5c9b74b8a4f398aa7a4012559577",
2
+ "cliVersion": "0.28.1-beta.2",
3
+ "sdkVersion": "0.16.1-beta.2",
4
+ "runtimeBuildId": "ae26f3f7d729",
5
+ "inputFingerprint": "ae26f3f7d7295446ac2eeefeefd3796000b0ff85798ee067d55becd93088a976",
6
6
  "entry": "index.js"
7
7
  }
package/dist/utils.js CHANGED
@@ -383,7 +383,7 @@ var DASHBOARD_API_ROUTES_DIRECTORY = "api";
383
383
  // ../better-auth/package.json
384
384
  var package_default = {
385
385
  name: "@playcademy/better-auth",
386
- version: "0.0.21-beta.1",
386
+ version: "0.0.21-beta.2",
387
387
  type: "module",
388
388
  exports: {
389
389
  "./server": {
@@ -2795,7 +2795,7 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as wr
2795
2795
  import { dirname as dirname4, join as join14 } from "node:path";
2796
2796
 
2797
2797
  // src/version.ts
2798
- var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.1";
2798
+ var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.2";
2799
2799
 
2800
2800
  // src/lib/build/binary-resource.ts
2801
2801
  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.28.1-beta.1";
2
+ var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.2";
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.28.1-beta.1",
3
+ "version": "0.28.1-beta.2",
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.16.1-beta.1",
58
+ "@playcademy/sdk": "0.16.1-beta.2",
59
59
  "chokidar": "^4.0.3",
60
60
  "colorette": "^2.0.20",
61
61
  "commander": "^14.0.1",