@playcademy/sandbox 0.6.1-beta.4 → 0.6.1-beta.5

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/server.js CHANGED
@@ -203,6 +203,20 @@ var init_auth = __esm(() => {
203
203
  };
204
204
  });
205
205
 
206
+ // ../constants/src/dashboard.ts
207
+ var DASHBOARD_USER_ROLES, DASHBOARD_WORKER_ROUTES, DASHBOARD_WORKER_SUFFIX = "-dash";
208
+ var init_dashboard = __esm(() => {
209
+ DASHBOARD_USER_ROLES = {
210
+ ADMIN: "admin",
211
+ VIEWER: "viewer"
212
+ };
213
+ DASHBOARD_WORKER_ROUTES = {
214
+ verifySession: "/sessions",
215
+ acceptInvite: "/invites/accept",
216
+ acceptReset: "/resets/accept"
217
+ };
218
+ });
219
+
206
220
  // ../constants/src/typescript.ts
207
221
  var init_typescript = () => {};
208
222
 
@@ -244,17 +258,8 @@ var init_platform = __esm(() => {
244
258
  var PLATFORM_TIMEZONE = "America/New_York";
245
259
 
246
260
  // ../constants/src/timeback.ts
247
- var TIMEBACK_ROUTES, TIMEBACK_ORG_SOURCED_ID = "PLAYCADEMY", TIMEBACK_ORG_NAME = "Playcademy Studios", TIMEBACK_ORG_TYPE = "department", TIMEBACK_COURSE_DEFAULTS, TIMEBACK_RESOURCE_DEFAULTS, TIMEBACK_COMPONENT_DEFAULTS, TIMEBACK_COMPONENT_RESOURCE_DEFAULTS, TIMEBACK_GAME_METRIC_DECIMAL_PLACES, TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE;
261
+ var TIMEBACK_ORG_SOURCED_ID = "PLAYCADEMY", TIMEBACK_ORG_NAME = "Playcademy Studios", TIMEBACK_ORG_TYPE = "department", TIMEBACK_COURSE_DEFAULTS, TIMEBACK_RESOURCE_DEFAULTS, TIMEBACK_COMPONENT_DEFAULTS, TIMEBACK_COMPONENT_RESOURCE_DEFAULTS, TIMEBACK_GAME_METRIC_DECIMAL_PLACES, TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE;
248
262
  var init_timeback2 = __esm(() => {
249
- TIMEBACK_ROUTES = {
250
- END_ACTIVITY: "/integrations/timeback/end-activity",
251
- GET_XP: "/integrations/timeback/xp",
252
- GET_MASTERY: "/integrations/timeback/mastery",
253
- GET_HIGHEST_GRADE_MASTERED: "/integrations/timeback/highest-grade-mastered",
254
- HEARTBEAT: "/integrations/timeback/heartbeat",
255
- ADVANCE_COURSE: "/integrations/timeback/advance-course",
256
- UNENROLL_COURSE: "/integrations/timeback/unenroll-course"
257
- };
258
263
  TIMEBACK_COURSE_DEFAULTS = {
259
264
  gradingScheme: "STANDARD",
260
265
  level: {
@@ -305,7 +310,7 @@ var init_timeback2 = __esm(() => {
305
310
  });
306
311
 
307
312
  // ../constants/src/cloudflare.ts
308
- var WORKER_NAMING, SECRETS_PREFIX = "secrets_", CLOUDFLARE_COMPATIBILITY_DATE = "2025-10-11";
313
+ var WORKER_NAMING, MAX_WORKER_NAME_LENGTH = 63, SECRETS_PREFIX = "secrets_", CLOUDFLARE_COMPATIBILITY_DATE = "2025-10-11";
309
314
  var init_cloudflare = __esm(() => {
310
315
  WORKER_NAMING = {
311
316
  STAGING_PREFIX: "staging-",
@@ -317,6 +322,7 @@ var init_cloudflare = __esm(() => {
317
322
  // ../constants/src/index.ts
318
323
  var init_src = __esm(() => {
319
324
  init_auth();
325
+ init_dashboard();
320
326
  init_typescript();
321
327
  init_domains();
322
328
  init_env_vars();
@@ -1056,8 +1062,7 @@ async function waitForPort(port, timeoutMs = 5000) {
1056
1062
  const start2 = Date.now();
1057
1063
  while (await isPortInUse(port)) {
1058
1064
  if (Date.now() - start2 > timeoutMs) {
1059
- throw new Error(`Port ${port} is already in use.
1060
- ` + `Stop the other server or specify a different port with --port <number>.`);
1065
+ throw new Error(`Port ${port} is already in use`);
1061
1066
  }
1062
1067
  await new Promise((resolve) => setTimeout(resolve, 100));
1063
1068
  }
@@ -1066,8 +1071,7 @@ async function requirePortAvailable(port, timeoutMs = 100) {
1066
1071
  const start2 = Date.now();
1067
1072
  while (await isPortInUse(port)) {
1068
1073
  if (Date.now() - start2 > timeoutMs) {
1069
- throw new Error(`Port ${port} is already in use.
1070
- ` + `Stop the other server or specify a different port with --port <number>.`);
1074
+ throw new Error(`Port ${port} is already in use`);
1071
1075
  }
1072
1076
  await new Promise((resolve) => setTimeout(resolve, 50));
1073
1077
  }
@@ -1079,7 +1083,7 @@ var package_default;
1079
1083
  var init_package = __esm(() => {
1080
1084
  package_default = {
1081
1085
  name: "@playcademy/sandbox",
1082
- version: "0.6.1-beta.4",
1086
+ version: "0.6.1-beta.5",
1083
1087
  description: "Local development server for Playcademy game development",
1084
1088
  type: "module",
1085
1089
  exports: {
@@ -1148,7 +1152,7 @@ var init_package = __esm(() => {
1148
1152
  });
1149
1153
 
1150
1154
  // ../api-core/src/errors/domain.error.ts
1151
- var DomainError, BadRequestError, AccessDeniedError, NotFoundError, ConflictError, AlreadyExistsError, ValidationError, InternalError, ServiceUnavailableError, TimeoutError;
1155
+ var DomainError, BadRequestError, UnauthorizedError, AccessDeniedError, NotFoundError, ConflictError, AlreadyExistsError, ValidationError, RateLimitError, InternalError, ServiceUnavailableError, TimeoutError;
1152
1156
  var init_domain_error = __esm(() => {
1153
1157
  DomainError = class DomainError extends Error {
1154
1158
  code;
@@ -1166,6 +1170,12 @@ var init_domain_error = __esm(() => {
1166
1170
  this.name = "BadRequestError";
1167
1171
  }
1168
1172
  };
1173
+ UnauthorizedError = class UnauthorizedError extends DomainError {
1174
+ constructor(message = "Unauthorized", details) {
1175
+ super("UNAUTHORIZED", message, details);
1176
+ this.name = "UnauthorizedError";
1177
+ }
1178
+ };
1169
1179
  AccessDeniedError = class AccessDeniedError extends DomainError {
1170
1180
  constructor(message = "Access denied", details) {
1171
1181
  super("ACCESS_DENIED", message, details);
@@ -1198,6 +1208,12 @@ var init_domain_error = __esm(() => {
1198
1208
  this.name = "ValidationError";
1199
1209
  }
1200
1210
  };
1211
+ RateLimitError = class RateLimitError extends DomainError {
1212
+ constructor(message = "Rate limit exceeded", details) {
1213
+ super("RATE_LIMITED", message, details);
1214
+ this.name = "RateLimitError";
1215
+ }
1216
+ };
1201
1217
  InternalError = class InternalError extends DomainError {
1202
1218
  constructor(message = "Internal error", details) {
1203
1219
  super("INTERNAL", message, details);
@@ -1556,12 +1572,24 @@ data: ${JSON.stringify(data)}
1556
1572
  return sseEncoder.encode(payload);
1557
1573
  }
1558
1574
  function createContextBuilder(options) {
1559
- const { db, config: config2, providers, services, cloudflare: cloudflare2, timeback: timeback2, resolveUser, resolveGameId } = options;
1575
+ const {
1576
+ db,
1577
+ config: config2,
1578
+ providers,
1579
+ services,
1580
+ cloudflare: cloudflare2,
1581
+ timeback: timeback2,
1582
+ resolveUser,
1583
+ resolveGameId,
1584
+ resolveApiKey
1585
+ } = options;
1560
1586
  return async (c) => {
1561
1587
  const user = resolveUser ? await resolveUser(c) : null;
1562
1588
  const gameId = resolveGameId ? await resolveGameId(c) : undefined;
1589
+ const apiKey = resolveApiKey ? await resolveApiKey(c) : undefined;
1563
1590
  return {
1564
1591
  user,
1592
+ apiKey,
1565
1593
  gameId,
1566
1594
  params: c.req.param(),
1567
1595
  url: new URL(c.req.url),
@@ -11180,7 +11208,7 @@ var init_table4 = __esm(() => {
11180
11208
  });
11181
11209
 
11182
11210
  // ../data/src/domains/game/table.ts
11183
- var gamePlatformEnum, gameTypeEnum, gameVisibilityEnum, games, gameMemberRoleEnum, gameMembers, gameMembersRelations, deploymentProviderEnum, deployJobStatusEnum, gameDeployments, gameDeployJobs, customHostnameStatusEnum, customHostnameSslStatusEnum, customHostnameEnvironmentEnum, gameCustomHostnames;
11211
+ var gamePlatformEnum, gameTypeEnum, gameVisibilityEnum, games, gameMemberRoleEnum, gameMembers, gameMembersRelations, gameDashboardUserRoleEnum, gameDashboardUsers, gameDashboardUsersRelations, deploymentProviderEnum, deploymentTargetEnum, deployJobStatusEnum, gameDeployments, gameDeployJobs, customHostnameStatusEnum, customHostnameSslStatusEnum, customHostnameEnvironmentEnum, gameCustomHostnames;
11184
11212
  var init_table5 = __esm(() => {
11185
11213
  init_drizzle_orm();
11186
11214
  init_pg_core();
@@ -11224,7 +11252,37 @@ var init_table5 = __esm(() => {
11224
11252
  references: [users.id]
11225
11253
  })
11226
11254
  }));
11255
+ gameDashboardUserRoleEnum = pgEnum("game_dashboard_user_role", [
11256
+ DASHBOARD_USER_ROLES.ADMIN,
11257
+ DASHBOARD_USER_ROLES.VIEWER
11258
+ ]);
11259
+ gameDashboardUsers = pgTable("game_dashboard_users", {
11260
+ id: uuid("id").primaryKey().defaultRandom(),
11261
+ gameId: uuid("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
11262
+ email: text("email").notNull(),
11263
+ displayName: text("display_name"),
11264
+ role: gameDashboardUserRoleEnum("role").notNull().default(DASHBOARD_USER_ROLES.VIEWER),
11265
+ passwordHash: text("password_hash"),
11266
+ inviteTokenHash: text("invite_token_hash"),
11267
+ inviteExpiresAt: timestamp("invite_expires_at", { withTimezone: true }),
11268
+ resetTokenHash: text("reset_token_hash"),
11269
+ resetExpiresAt: timestamp("reset_expires_at", { withTimezone: true }),
11270
+ failedLoginAttempts: integer("failed_login_attempts").notNull().default(0),
11271
+ lastFailedLoginAt: timestamp("last_failed_login_at", { withTimezone: true }),
11272
+ platformUserId: text("platform_user_id").references(() => users.id, {
11273
+ onDelete: "set null"
11274
+ }),
11275
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
11276
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
11277
+ }, (table3) => [uniqueIndex("game_dashboard_users_game_email_idx").on(table3.gameId, table3.email)]);
11278
+ gameDashboardUsersRelations = relations(gameDashboardUsers, ({ one }) => ({
11279
+ game: one(games, {
11280
+ fields: [gameDashboardUsers.gameId],
11281
+ references: [games.id]
11282
+ })
11283
+ }));
11227
11284
  deploymentProviderEnum = pgEnum("deployment_provider", ["cloudflare", "aws"]);
11285
+ deploymentTargetEnum = pgEnum("deployment_target", ["game", "dashboard"]);
11228
11286
  deployJobStatusEnum = pgEnum("deploy_job_status", [
11229
11287
  "pending",
11230
11288
  "running",
@@ -11236,6 +11294,7 @@ var init_table5 = __esm(() => {
11236
11294
  gameId: uuid("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
11237
11295
  deploymentId: text("deployment_id").notNull(),
11238
11296
  provider: deploymentProviderEnum("provider").notNull(),
11297
+ target: deploymentTargetEnum("target").notNull().default("game"),
11239
11298
  url: text("url").notNull(),
11240
11299
  codeHash: text("code_hash"),
11241
11300
  isActive: boolean("is_active").notNull().default(false),
@@ -11423,8 +11482,12 @@ __export(exports_tables_index, {
11423
11482
  gameMemberRoleEnum: () => gameMemberRoleEnum,
11424
11483
  gameDeployments: () => gameDeployments,
11425
11484
  gameDeployJobs: () => gameDeployJobs,
11485
+ gameDashboardUsersRelations: () => gameDashboardUsersRelations,
11486
+ gameDashboardUsers: () => gameDashboardUsers,
11487
+ gameDashboardUserRoleEnum: () => gameDashboardUserRoleEnum,
11426
11488
  gameCustomHostnames: () => gameCustomHostnames,
11427
11489
  developerStatusEnum: () => developerStatusEnum,
11490
+ deploymentTargetEnum: () => deploymentTargetEnum,
11428
11491
  deploymentProviderEnum: () => deploymentProviderEnum,
11429
11492
  deployJobStatusEnum: () => deployJobStatusEnum,
11430
11493
  customHostnameStatusEnum: () => customHostnameStatusEnum,
@@ -12928,6 +12991,10 @@ function errorMessage(err2) {
12928
12991
  function errorType(err2) {
12929
12992
  return err2 instanceof Error ? err2.constructor.name : typeof err2;
12930
12993
  }
12994
+ function isUniqueViolation(err2) {
12995
+ return typeof err2 === "object" && err2 !== null && err2.code === PG_UNIQUE_VIOLATION;
12996
+ }
12997
+ var PG_UNIQUE_VIOLATION = "23505";
12931
12998
 
12932
12999
  // ../otel/src/spans.ts
12933
13000
  function truncate(value) {
@@ -13006,6 +13073,310 @@ var init_spans = __esm(() => {
13006
13073
  ROOT_SPAN_KEY = import_api2.createContextKey("playcademy.root_span");
13007
13074
  });
13008
13075
 
13076
+ // ../utils/src/random.ts
13077
+ async function generateSecureRandomString(length) {
13078
+ const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
13079
+ const randomValues = new Uint8Array(length);
13080
+ crypto.getRandomValues(randomValues);
13081
+ return [...randomValues].map((byte) => charset[byte % charset.length]).join("");
13082
+ }
13083
+
13084
+ // ../api-core/src/utils/hash.util.ts
13085
+ async function sha256Hex(input) {
13086
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
13087
+ return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
13088
+ }
13089
+
13090
+ // ../api-core/src/utils/dashboard.util.ts
13091
+ function dashboardCredentialScope(slug) {
13092
+ return `${CREDENTIAL_SCOPE_PREFIX}${slug}`;
13093
+ }
13094
+ function dashboardCredentialSlugs(permissions) {
13095
+ return (permissions?.[DASHBOARD_PERMISSION_NAMESPACE] ?? []).filter((scope) => scope.startsWith(CREDENTIAL_SCOPE_PREFIX)).map((scope) => scope.slice(CREDENTIAL_SCOPE_PREFIX.length)).filter((slug) => slug.length > 0);
13096
+ }
13097
+ function isAllowedDashboardWorkerRequest(method, pathname, permissions) {
13098
+ const path = pathname.replace(/\/+$/, "");
13099
+ return dashboardCredentialSlugs(permissions).some((slug) => {
13100
+ if (method === "GET") {
13101
+ return path === `/api/games/${slug}`;
13102
+ }
13103
+ if (method === "POST") {
13104
+ return Object.values(DASHBOARD_WORKER_ROUTES).some((subpath) => path === `/api/games/${slug}/dashboard${subpath}`);
13105
+ }
13106
+ return false;
13107
+ });
13108
+ }
13109
+ function hashDashboardToken(token) {
13110
+ return sha256Hex(token);
13111
+ }
13112
+ function loginBackoffMs(failedAttempts) {
13113
+ if (failedAttempts < LOGIN_BACKOFF_THRESHOLD) {
13114
+ return 0;
13115
+ }
13116
+ return Math.min(LOGIN_BACKOFF_CAP_MS, LOGIN_BACKOFF_BASE_MS * 2 ** (failedAttempts - LOGIN_BACKOFF_THRESHOLD));
13117
+ }
13118
+ var DASHBOARD_PERMISSION_NAMESPACE = "dashboard", DASHBOARD_WORKER_KEY_RESTRICTED = "The dashboard worker key is restricted to dashboard runtime endpoints", CREDENTIAL_SCOPE_PREFIX = "credentials:", LOGIN_BACKOFF_THRESHOLD = 5, LOGIN_BACKOFF_BASE_MS = 1000, LOGIN_BACKOFF_CAP_MS;
13119
+ var init_dashboard_util = __esm(() => {
13120
+ init_src();
13121
+ LOGIN_BACKOFF_CAP_MS = 5 * 60 * 1000;
13122
+ });
13123
+
13124
+ // ../api-core/src/services/dashboard.service.ts
13125
+ function alreadyExists(gameId) {
13126
+ return new AlreadyExistsError("A dashboard user with this email already exists", { gameId });
13127
+ }
13128
+ var DashboardService;
13129
+ var init_dashboard_service = __esm(() => {
13130
+ init_drizzle_orm();
13131
+ init_tables_index();
13132
+ init_spans();
13133
+ init_errors();
13134
+ init_dashboard_util();
13135
+ DashboardService = class DashboardService {
13136
+ deps;
13137
+ static INVITE_TOKEN_LENGTH = 48;
13138
+ static INVITE_TTL_MS = 72 * 60 * 60 * 1000;
13139
+ static RESET_TTL_MS = 24 * 60 * 60 * 1000;
13140
+ constructor(deps) {
13141
+ this.deps = deps;
13142
+ }
13143
+ async listUsers(slug, user) {
13144
+ const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
13145
+ const rows = await this.deps.db.select({
13146
+ id: gameDashboardUsers.id,
13147
+ gameId: gameDashboardUsers.gameId,
13148
+ email: gameDashboardUsers.email,
13149
+ displayName: gameDashboardUsers.displayName,
13150
+ role: gameDashboardUsers.role,
13151
+ platformUserId: gameDashboardUsers.platformUserId,
13152
+ createdAt: gameDashboardUsers.createdAt,
13153
+ updatedAt: gameDashboardUsers.updatedAt,
13154
+ pending: sql`(${gameDashboardUsers.passwordHash} IS NULL)`
13155
+ }).from(gameDashboardUsers).where(eq(gameDashboardUsers.gameId, game2.id)).orderBy(asc(gameDashboardUsers.createdAt));
13156
+ setAttributes({
13157
+ "app.dashboard.operation": "list_users",
13158
+ "app.dashboard.result_count": rows.length
13159
+ });
13160
+ return rows;
13161
+ }
13162
+ async addUser(slug, user, input) {
13163
+ const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
13164
+ const email = input.email.toLowerCase();
13165
+ setAttributes({
13166
+ "app.dashboard.operation": "add_user",
13167
+ "app.dashboard.user_role": input.role
13168
+ });
13169
+ const existing = await this.findByEmail(game2.id, email);
13170
+ if (existing) {
13171
+ throw alreadyExists(game2.id);
13172
+ }
13173
+ const inviteToken = await generateSecureRandomString(DashboardService.INVITE_TOKEN_LENGTH);
13174
+ let created;
13175
+ try {
13176
+ [created] = await this.deps.db.insert(gameDashboardUsers).values({
13177
+ gameId: game2.id,
13178
+ email,
13179
+ displayName: input.displayName,
13180
+ role: input.role,
13181
+ inviteTokenHash: await hashDashboardToken(inviteToken),
13182
+ inviteExpiresAt: new Date(Date.now() + DashboardService.INVITE_TTL_MS),
13183
+ platformUserId: email === user.email.toLowerCase() ? user.id : undefined
13184
+ }).returning();
13185
+ } catch (error) {
13186
+ if (isUniqueViolation(error)) {
13187
+ throw alreadyExists(game2.id);
13188
+ }
13189
+ throw error;
13190
+ }
13191
+ if (!created) {
13192
+ throw new ValidationError("Failed to create dashboard user");
13193
+ }
13194
+ return { user: DashboardService.toSummary(created), token: inviteToken, kind: "invite" };
13195
+ }
13196
+ async removeUser(slug, user, dashboardUserId) {
13197
+ const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
13198
+ setAttributes({
13199
+ "app.dashboard.operation": "remove_user",
13200
+ "app.dashboard.user_id": dashboardUserId
13201
+ });
13202
+ const [deleted] = await this.deps.db.delete(gameDashboardUsers).where(and(eq(gameDashboardUsers.gameId, game2.id), eq(gameDashboardUsers.id, dashboardUserId))).returning({ id: gameDashboardUsers.id });
13203
+ if (!deleted) {
13204
+ throw new NotFoundError("Dashboard user", dashboardUserId);
13205
+ }
13206
+ }
13207
+ async verifyLogin(slug, input) {
13208
+ const game2 = await this.getGameForRuntime(slug);
13209
+ setAttributes({ "app.dashboard.operation": "verify_login" });
13210
+ const dashboardUser = await this.findByEmail(game2.id, input.email.toLowerCase());
13211
+ if (!dashboardUser?.passwordHash) {
13212
+ throw new UnauthorizedError("Invalid credentials");
13213
+ }
13214
+ if (dashboardUser.lastFailedLoginAt) {
13215
+ const retryAt = dashboardUser.lastFailedLoginAt.getTime() + loginBackoffMs(dashboardUser.failedLoginAttempts);
13216
+ if (retryAt > Date.now()) {
13217
+ addEvent("dashboard.login_throttled", {
13218
+ "app.dashboard.failed_attempts": dashboardUser.failedLoginAttempts
13219
+ });
13220
+ throw new RateLimitError("Too many failed attempts — try again shortly", {
13221
+ retryAfterSeconds: Math.ceil((retryAt - Date.now()) / 1000)
13222
+ });
13223
+ }
13224
+ }
13225
+ const valid = await this.deps.verifyPassword({
13226
+ hash: dashboardUser.passwordHash,
13227
+ password: input.password
13228
+ });
13229
+ if (!valid) {
13230
+ await this.deps.db.update(gameDashboardUsers).set({
13231
+ failedLoginAttempts: sql`${gameDashboardUsers.failedLoginAttempts} + 1`,
13232
+ lastFailedLoginAt: new Date
13233
+ }).where(eq(gameDashboardUsers.id, dashboardUser.id));
13234
+ throw new UnauthorizedError("Invalid credentials");
13235
+ }
13236
+ if (dashboardUser.failedLoginAttempts > 0) {
13237
+ await this.deps.db.update(gameDashboardUsers).set({ failedLoginAttempts: 0, lastFailedLoginAt: null }).where(eq(gameDashboardUsers.id, dashboardUser.id));
13238
+ }
13239
+ return DashboardService.toSummary(dashboardUser);
13240
+ }
13241
+ async acceptInvite(slug, input) {
13242
+ const game2 = await this.getGameForRuntime(slug);
13243
+ setAttributes({ "app.dashboard.operation": "accept_invite" });
13244
+ const tokenHash = await hashDashboardToken(input.token);
13245
+ const invited = await this.deps.db.query.gameDashboardUsers.findFirst({
13246
+ where: and(eq(gameDashboardUsers.gameId, game2.id), eq(gameDashboardUsers.inviteTokenHash, tokenHash))
13247
+ });
13248
+ if (!invited) {
13249
+ throw new UnauthorizedError("Invalid or already-used invite token");
13250
+ }
13251
+ if (invited.inviteExpiresAt && invited.inviteExpiresAt.getTime() < Date.now()) {
13252
+ throw new UnauthorizedError("This invite has expired — ask for a new one");
13253
+ }
13254
+ const passwordHash = await this.deps.hashPassword(input.password);
13255
+ const [updated] = await this.deps.db.update(gameDashboardUsers).set({
13256
+ passwordHash,
13257
+ inviteTokenHash: null,
13258
+ inviteExpiresAt: null,
13259
+ updatedAt: new Date
13260
+ }).where(and(eq(gameDashboardUsers.id, invited.id), eq(gameDashboardUsers.inviteTokenHash, tokenHash), isNull(gameDashboardUsers.passwordHash))).returning();
13261
+ if (!updated) {
13262
+ throw new UnauthorizedError("Invalid or already-used invite token");
13263
+ }
13264
+ return DashboardService.toSummary(updated);
13265
+ }
13266
+ async acceptReset(slug, input) {
13267
+ const game2 = await this.getGameForRuntime(slug);
13268
+ setAttributes({ "app.dashboard.operation": "accept_reset" });
13269
+ const tokenHash = await hashDashboardToken(input.token);
13270
+ const found = await this.deps.db.query.gameDashboardUsers.findFirst({
13271
+ where: and(eq(gameDashboardUsers.gameId, game2.id), eq(gameDashboardUsers.resetTokenHash, tokenHash))
13272
+ });
13273
+ if (!found) {
13274
+ throw new UnauthorizedError("Invalid or already-used reset token");
13275
+ }
13276
+ if (found.resetExpiresAt && found.resetExpiresAt.getTime() < Date.now()) {
13277
+ throw new UnauthorizedError("This reset link has expired — ask for a new one");
13278
+ }
13279
+ const passwordHash = await this.deps.hashPassword(input.password);
13280
+ const [updated] = await this.deps.db.update(gameDashboardUsers).set({
13281
+ passwordHash,
13282
+ resetTokenHash: null,
13283
+ resetExpiresAt: null,
13284
+ inviteTokenHash: null,
13285
+ inviteExpiresAt: null,
13286
+ failedLoginAttempts: 0,
13287
+ lastFailedLoginAt: null,
13288
+ updatedAt: new Date
13289
+ }).where(and(eq(gameDashboardUsers.id, found.id), eq(gameDashboardUsers.resetTokenHash, tokenHash))).returning();
13290
+ if (!updated) {
13291
+ throw new UnauthorizedError("Invalid or already-used reset token");
13292
+ }
13293
+ return DashboardService.toSummary(updated);
13294
+ }
13295
+ async issueRecoveryLink(slug, user, dashboardUserId) {
13296
+ const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
13297
+ const existing = await this.deps.db.query.gameDashboardUsers.findFirst({
13298
+ where: and(eq(gameDashboardUsers.gameId, game2.id), eq(gameDashboardUsers.id, dashboardUserId))
13299
+ });
13300
+ if (!existing) {
13301
+ throw new NotFoundError("Dashboard user", dashboardUserId);
13302
+ }
13303
+ const kind = existing.passwordHash ? "reset" : "invite";
13304
+ setAttributes({
13305
+ "app.dashboard.operation": "issue_recovery_link",
13306
+ "app.dashboard.recovery_kind": kind
13307
+ });
13308
+ const token = await generateSecureRandomString(DashboardService.INVITE_TOKEN_LENGTH);
13309
+ const tokenHash = await hashDashboardToken(token);
13310
+ const fields = kind === "invite" ? {
13311
+ inviteTokenHash: tokenHash,
13312
+ inviteExpiresAt: new Date(Date.now() + DashboardService.INVITE_TTL_MS)
13313
+ } : {
13314
+ resetTokenHash: tokenHash,
13315
+ resetExpiresAt: new Date(Date.now() + DashboardService.RESET_TTL_MS)
13316
+ };
13317
+ const [updated] = await this.deps.db.update(gameDashboardUsers).set({ ...fields, updatedAt: new Date }).where(eq(gameDashboardUsers.id, existing.id)).returning();
13318
+ if (!updated) {
13319
+ throw new NotFoundError("Dashboard user", dashboardUserId);
13320
+ }
13321
+ return { user: DashboardService.toSummary(updated), token, kind };
13322
+ }
13323
+ async getGameForRuntime(slug) {
13324
+ const game2 = await this.deps.db.query.games.findFirst({
13325
+ where: eq(games.slug, slug),
13326
+ columns: { id: true }
13327
+ });
13328
+ if (!game2) {
13329
+ throw new NotFoundError("Game", slug);
13330
+ }
13331
+ return game2;
13332
+ }
13333
+ async findByEmail(gameId, email) {
13334
+ const row = await this.deps.db.query.gameDashboardUsers.findFirst({
13335
+ where: and(eq(gameDashboardUsers.gameId, gameId), eq(gameDashboardUsers.email, email))
13336
+ });
13337
+ return row ?? null;
13338
+ }
13339
+ static toSummary(row) {
13340
+ return {
13341
+ id: row.id,
13342
+ gameId: row.gameId,
13343
+ email: row.email,
13344
+ displayName: row.displayName,
13345
+ role: row.role,
13346
+ platformUserId: row.platformUserId,
13347
+ createdAt: row.createdAt,
13348
+ updatedAt: row.updatedAt,
13349
+ pending: !row.passwordHash
13350
+ };
13351
+ }
13352
+ };
13353
+ });
13354
+
13355
+ // ../data/src/domains/game/helpers.ts
13356
+ function activeDeploymentWhere(gameId, target = "game") {
13357
+ return and(eq(gameDeployments.gameId, gameId), eq(gameDeployments.target, target), eq(gameDeployments.isActive, true));
13358
+ }
13359
+ var init_helpers = __esm(() => {
13360
+ init_drizzle_orm();
13361
+ init_table5();
13362
+ });
13363
+
13364
+ // ../data/src/domains/timeback/helpers.ts
13365
+ function isActiveGameTimebackIntegrationStatus(statusColumn = gameTimebackIntegrations.status) {
13366
+ return sql`${statusColumn} IS DISTINCT FROM ${DEACTIVATED_GAME_TIMEBACK_INTEGRATION_STATUS}`;
13367
+ }
13368
+ var ACTIVE_GAME_TIMEBACK_INTEGRATION_STATUS = "active", DEACTIVATED_GAME_TIMEBACK_INTEGRATION_STATUS = "deactivated";
13369
+ var init_helpers2 = __esm(() => {
13370
+ init_drizzle_orm();
13371
+ init_table7();
13372
+ });
13373
+
13374
+ // ../data/src/helpers.index.ts
13375
+ var init_helpers_index = __esm(() => {
13376
+ init_helpers();
13377
+ init_helpers2();
13378
+ });
13379
+
13009
13380
  // ../../node_modules/.bun/process-nextick-args@2.0.1/node_modules/process-nextick-args/index.js
13010
13381
  var require_process_nextick_args = __commonJS((exports, module2) => {
13011
13382
  if (typeof process === "undefined" || !process.version || process.version.indexOf("v0.") === 0 || process.version.indexOf("v1.") === 0 && process.version.indexOf("v1.8.") !== 0) {
@@ -22086,8 +22457,8 @@ var require_lib3 = __commonJS((exports, module2) => {
22086
22457
  });
22087
22458
 
22088
22459
  // ../utils/src/zip.ts
22089
- import { mkdir, writeFile } from "fs/promises";
22090
- import { join as join2 } from "path";
22460
+ import { mkdir, readdir, readFile, writeFile } from "fs/promises";
22461
+ import { join as join2, relative, sep } from "path";
22091
22462
  async function extractZipToDirectory(zipBuffer, targetDir) {
22092
22463
  try {
22093
22464
  const zip = await import_jszip.default.loadAsync(zipBuffer);
@@ -22113,9 +22484,10 @@ async function extractZipToDirectory(zipBuffer, targetDir) {
22113
22484
  fileCount: Object.keys(zip.files).length
22114
22485
  });
22115
22486
  } catch (error) {
22116
- const errorMessage2 = error instanceof Error ? error.message : String(error);
22117
22487
  log.error("[utils/zip] Failed to extract ZIP", { targetDir, error });
22118
- throw new Error(`Failed to extract ZIP to ${targetDir}: ${errorMessage2}`, { cause: error });
22488
+ throw new Error(`Failed to extract ZIP to ${targetDir}: ${errorMessage(error)}`, {
22489
+ cause: error
22490
+ });
22119
22491
  }
22120
22492
  }
22121
22493
  var import_jszip;
@@ -22385,6 +22757,7 @@ class DeployJobService {
22385
22757
  jobId,
22386
22758
  leaseId,
22387
22759
  leaseLost,
22760
+ target,
22388
22761
  game: game2,
22389
22762
  user,
22390
22763
  error
@@ -22414,9 +22787,12 @@ class DeployJobService {
22414
22787
  }
22415
22788
  }
22416
22789
  if (!effectiveLeaseLost) {
22417
- await this.deps.notifyDeploymentFailure(game2.slug, game2.displayName, message, {
22418
- id: user.id,
22419
- email: user.email
22790
+ await this.deps.notifyDeploymentFailure({
22791
+ slug: game2.slug,
22792
+ displayName: game2.displayName,
22793
+ error: message,
22794
+ target,
22795
+ developer: { id: user.id, email: user.email }
22420
22796
  });
22421
22797
  }
22422
22798
  await this.deleteCodeBundle(jobId);
@@ -22518,7 +22894,7 @@ class DeployJobService {
22518
22894
  }
22519
22895
  assertLease();
22520
22896
  const activeDeployment = await this.deps.db.query.gameDeployments.findFirst({
22521
- where: and(eq(gameDeployments.gameId, job.gameId), eq(gameDeployments.isActive, true)),
22897
+ where: activeDeploymentWhere(job.gameId, request.target ?? "game"),
22522
22898
  columns: {
22523
22899
  deploymentId: true,
22524
22900
  url: true
@@ -22541,7 +22917,15 @@ class DeployJobService {
22541
22917
  } catch (error) {
22542
22918
  clearInterval(heartbeat);
22543
22919
  setAttribute("app.deploy_job.run_duration_ms", DeployJobService.elapsedMsSince(new Date(runStartedAt)));
22544
- await this.handleRunError({ jobId, leaseId, leaseLost, game: game2, user, error });
22920
+ await this.handleRunError({
22921
+ jobId,
22922
+ leaseId,
22923
+ leaseLost,
22924
+ target: request.target ?? "game",
22925
+ game: game2,
22926
+ user,
22927
+ error
22928
+ });
22545
22929
  throw error;
22546
22930
  }
22547
22931
  }
@@ -22560,6 +22944,7 @@ async function forceMarkDeployJobFailed(db2, jobId, error) {
22560
22944
  var STATUS_MAP2, DEPLOY_JOB_LEASE_MS, DEPLOY_JOB_HEARTBEAT_MS, DEPLOY_JOB_CODE_BUNDLE_PREFIX = "deploy-job-code";
22561
22945
  var init_deploy_job_service = __esm(() => {
22562
22946
  init_drizzle_orm();
22947
+ init_helpers_index();
22563
22948
  init_tables_index();
22564
22949
  init_spans();
22565
22950
  init_zip();
@@ -24703,7 +25088,7 @@ var init_bindings = __esm(() => {
24703
25088
  });
24704
25089
 
24705
25090
  // ../cloudflare/src/playcademy/provider/helpers.ts
24706
- var init_helpers = __esm(() => {
25091
+ var init_helpers3 = __esm(() => {
24707
25092
  init_mime();
24708
25093
  });
24709
25094
 
@@ -24715,7 +25100,7 @@ var init_provider = __esm(() => {
24715
25100
  init_constants2();
24716
25101
  init_assets_config();
24717
25102
  init_bindings();
24718
- init_helpers();
25103
+ init_helpers3();
24719
25104
  });
24720
25105
  // ../cloudflare/src/playcademy/provider/index.ts
24721
25106
  var init_provider2 = __esm(() => {
@@ -27166,7 +27551,7 @@ var init_stages = __esm(() => {
27166
27551
  });
27167
27552
 
27168
27553
  // ../api-core/src/utils/deployment.util.ts
27169
- function getDeploymentId(gameSlug, sstStage) {
27554
+ function getGameDeploymentId(gameSlug, sstStage) {
27170
27555
  if (sstStage === "production") {
27171
27556
  return gameSlug;
27172
27557
  }
@@ -27175,45 +27560,57 @@ function getDeploymentId(gameSlug, sstStage) {
27175
27560
  }
27176
27561
  return `${WORKER_NAMING.LOCAL_PREFIX}${sstStage}-${gameSlug}`;
27177
27562
  }
27563
+ function getDashboardDeploymentId(gameSlug, sstStage) {
27564
+ return `${getGameDeploymentId(gameSlug, sstStage)}${DASHBOARD_WORKER_SUFFIX}`;
27565
+ }
27178
27566
  function getGameWorkerApiKeyName(slug) {
27179
- return `game-worker-${slug}`.substring(0, 32);
27567
+ return `${GAME_WORKER_KEY_PREFIX}${slug}`.substring(0, 32);
27568
+ }
27569
+ function getDashboardWorkerApiKeyName(slug) {
27570
+ return `${DASHBOARD_WORKER_KEY_PREFIX}${slug}`;
27180
27571
  }
27181
27572
  function toBindingName(queueKey) {
27182
27573
  return `${queueKey.replace(/-/g, "_").toUpperCase()}_QUEUE`;
27183
27574
  }
27184
- async function generateDeploymentHash(code) {
27185
- const encoder = new TextEncoder;
27186
- const data = encoder.encode(code);
27187
- const hashBuffer = await crypto.subtle.digest("SHA-256", data);
27188
- const hashArray = [...new Uint8Array(hashBuffer)];
27189
- return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
27575
+ function generateDeploymentHash(code) {
27576
+ return sha256Hex(code);
27190
27577
  }
27578
+ var GAME_WORKER_KEY_PREFIX = "game-worker-", DASHBOARD_WORKER_KEY_PREFIX = "dash-worker-";
27191
27579
  var init_deployment_util = __esm(() => {
27192
27580
  init_src();
27193
27581
  init_stages();
27194
27582
  });
27195
27583
 
27584
+ // ../api-core/src/utils/worker-keys.util.ts
27585
+ async function sweepDashboardWorkerKeys(deleteApiKeysByName, slug) {
27586
+ try {
27587
+ await deleteApiKeysByName(getDashboardWorkerApiKeyName(slug));
27588
+ } catch (error) {
27589
+ addEvent("dashboard.worker_key_sweep_failed", {
27590
+ "exception.type": errorType(error),
27591
+ "app.error.message": errorMessage(error)
27592
+ });
27593
+ }
27594
+ }
27595
+ var init_worker_keys_util = __esm(() => {
27596
+ init_spans();
27597
+ init_deployment_util();
27598
+ });
27599
+
27196
27600
  // ../api-core/src/services/deploy.service.ts
27601
+ function readDashboardTheme(config2) {
27602
+ const theme = config2?.dashboard?.theme;
27603
+ return {
27604
+ ...typeof theme?.primary === "string" && { primary: theme.primary },
27605
+ ...typeof theme?.secondary === "string" && { secondary: theme.secondary }
27606
+ };
27607
+ }
27608
+
27197
27609
  class DeployService {
27198
27610
  deps;
27199
27611
  constructor(deps) {
27200
27612
  this.deps = deps;
27201
27613
  }
27202
- static classifyDeployType(flags2) {
27203
- if (flags2.hasBackend && flags2.hasFrontend) {
27204
- return "full_stack";
27205
- }
27206
- if (flags2.hasFrontend) {
27207
- return "frontend_only";
27208
- }
27209
- if (flags2.hasBackend) {
27210
- return "backend_only";
27211
- }
27212
- return "metadata_only";
27213
- }
27214
- static countDeadLetterQueues(bindings) {
27215
- return bindings?.queues?.filter((queue) => Boolean(queue.deadLetterQueue)).length ?? 0;
27216
- }
27217
27614
  getCloudflare() {
27218
27615
  const cf = this.deps.cloudflare;
27219
27616
  if (!cf) {
@@ -27221,86 +27618,307 @@ class DeployService {
27221
27618
  }
27222
27619
  return cf;
27223
27620
  }
27224
- async createApiKey(user, slug, keyName) {
27225
- const { key: apiKey } = await this.deps.createAuthApiKey({
27226
- userId: user.id,
27227
- name: keyName,
27228
- expiresIn: null,
27229
- permissions: {
27230
- games: [`read:${slug}`, `write:${slug}`]
27231
- },
27232
- rateLimitEnabled: false
27233
- });
27234
- setAttribute("app.deploy.api_key_outcome", "created");
27235
- return apiKey;
27236
- }
27237
- async regenerateApiKey(user, slug, existingKeyId, keyName) {
27238
- if (existingKeyId) {
27239
- setAttribute("app.deploy.api_key_outcome", "regenerated");
27240
- try {
27241
- await this.deps.deleteAuthApiKey(existingKeyId);
27242
- } catch (error) {
27243
- addEvent("deploy.api_key_revoke_failed", {
27244
- "exception.type": errorType(error),
27245
- "app.error.message": errorMessage(error),
27246
- "app.deploy.old_key_id": existingKeyId
27247
- });
27621
+ async* deploy(slug, request, user, uploadDeps, extractZip) {
27622
+ const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
27623
+ const context2 = { slug, request, user, game: game2, uploadDeps, extractZip };
27624
+ switch (request.target ?? "game") {
27625
+ case "dashboard": {
27626
+ yield* this.deployDashboard(context2);
27627
+ break;
27628
+ }
27629
+ case "game": {
27630
+ yield* this.deployGame(context2);
27631
+ break;
27632
+ }
27633
+ default: {
27634
+ throw new ValidationError("Invalid deployment target");
27248
27635
  }
27249
27636
  }
27250
- return this.createApiKey(user, slug, keyName);
27251
27637
  }
27252
- async ensureApiKeyOnWorker(user, slug, deploymentId) {
27638
+ async* deployGame(context2) {
27639
+ const { slug, request, user, game: game2, uploadDeps, extractZip } = context2;
27253
27640
  const cf = this.getCloudflare();
27254
- const keyName = getGameWorkerApiKeyName(slug);
27255
- const existingKey = await this.deps.db.query.apikey.findFirst({
27256
- where: and(eq(apikey.userId, user.id), eq(apikey.name, keyName)),
27641
+ const db2 = this.deps.db;
27642
+ const flags2 = this.validateGameRequest(request);
27643
+ const { hasBackend, hasFrontend } = flags2;
27644
+ const deploymentId = getGameDeploymentId(slug, this.deps.config.sstStage);
27645
+ let frontendAssetsPath;
27646
+ let tempDir;
27647
+ if (hasFrontend) {
27648
+ if (!uploadDeps || !extractZip) {
27649
+ throw new ValidationError("Upload dependencies not configured for frontend deployment");
27650
+ }
27651
+ yield { type: "status", data: { message: "Fetching temporary files" } };
27652
+ const extracted = await this.fetchAndExtractFrontendAssets(slug, game2.id, request.uploadToken, uploadDeps, extractZip);
27653
+ tempDir = extracted.tempDir;
27654
+ frontendAssetsPath = extracted.assetsPath;
27655
+ yield { type: "status", data: { message: "Extracting assets" } };
27656
+ }
27657
+ const platformBaseUrl = await this.resolvePlatformBaseUrl();
27658
+ const env = {
27659
+ GAME_ID: game2.id,
27660
+ PLAYCADEMY_BASE_URL: platformBaseUrl,
27661
+ PLAYCADEMY_PLATFORM_SERVICE_JWKS: this.deps.config.platformServiceJwt?.publicJwks
27662
+ };
27663
+ yield {
27664
+ type: "status",
27665
+ data: { message: hasBackend ? "Deploying backend code" : "Deploying to platform" }
27666
+ };
27667
+ const keepAssets = hasBackend && !hasFrontend;
27668
+ const deploymentOptions = this.mapGameBindingsToOptions(deploymentId, request.bindings, request.schema);
27669
+ const bindings = deploymentOptions?.bindings;
27670
+ setAttributes({
27671
+ "app.deploy.has_d1": Boolean(bindings?.d1?.length),
27672
+ "app.deploy.has_kv": Boolean(bindings?.kv?.length),
27673
+ "app.deploy.has_r2": Boolean(bindings?.r2?.length),
27674
+ "app.deploy.queue_count": bindings?.queues?.length ?? 0,
27675
+ "app.deploy.dead_letter_queue_count": DeployService.countDeadLetterQueues(bindings)
27676
+ });
27677
+ const activeDeployment = await db2.query.gameDeployments.findFirst({
27678
+ where: activeDeploymentWhere(game2.id, "game"),
27679
+ columns: { resources: true }
27680
+ });
27681
+ if (deploymentOptions?.bindings?.d1?.length) {
27682
+ await this.cleanupOrphanD1Databases(cf, deploymentOptions.bindings.d1, slug, game2.id);
27683
+ }
27684
+ const result = await this.deployToCloudflare({
27685
+ deploymentId,
27686
+ code: request.code,
27687
+ env,
27688
+ tempDir,
27689
+ options: {
27690
+ ...deploymentOptions,
27691
+ compatibilityDate: request.compatibilityDate ?? CLOUDFLARE_COMPATIBILITY_DATE,
27692
+ compatibilityFlags: request.compatibilityFlags,
27693
+ existingResources: activeDeployment?.resources ?? undefined,
27694
+ assetsPath: frontendAssetsPath,
27695
+ keepAssets
27696
+ }
27697
+ });
27698
+ yield { type: "status", data: { message: "Finalizing deployment" } };
27699
+ const updatedGame = await this.finalizeGameDeployment({
27700
+ game: game2,
27701
+ slug,
27702
+ deploymentId,
27703
+ result,
27704
+ request,
27705
+ user,
27706
+ flags: flags2
27707
+ });
27708
+ yield { type: "complete", data: updatedGame };
27709
+ }
27710
+ async* deployDashboard(context2) {
27711
+ const { slug, request, user, game: game2 } = context2;
27712
+ const db2 = this.deps.db;
27713
+ const contract = this.validateDashboardRequest(request, context2.uploadDeps, context2.extractZip);
27714
+ const deploymentId = getDashboardDeploymentId(slug, this.deps.config.sstStage);
27715
+ if (deploymentId.length > MAX_WORKER_NAME_LENGTH) {
27716
+ throw new ValidationError(`Dashboard worker name '${deploymentId}' exceeds Cloudflare's ${MAX_WORKER_NAME_LENGTH}-character limit — shorten the game slug`);
27717
+ }
27718
+ const collidingGame = await db2.query.games.findFirst({
27719
+ where: eq(games.slug, `${slug}${DASHBOARD_WORKER_SUFFIX}`),
27257
27720
  columns: { id: true }
27258
27721
  });
27259
- let apiKey;
27260
- if (!existingKey) {
27261
- apiKey = await this.createApiKey(user, slug, keyName);
27262
- } else {
27263
- try {
27264
- const workerSecrets = await cf.listSecrets(deploymentId);
27265
- if (workerSecrets.includes("PLAYCADEMY_API_KEY")) {
27266
- setAttribute("app.deploy.api_key_outcome", "already_set");
27267
- return;
27268
- }
27269
- } catch (error) {
27270
- addEvent("deploy.worker_secrets_check_failed", {
27271
- "exception.type": errorType(error),
27272
- "app.error.message": errorMessage(error)
27273
- });
27722
+ if (collidingGame) {
27723
+ throw new ValidationError(`Cannot deploy this dashboard: an existing game's slug is '${slug}${DASHBOARD_WORKER_SUFFIX}', which owns the '${deploymentId}' worker name`);
27724
+ }
27725
+ const gameDeployment = await db2.query.gameDeployments.findFirst({
27726
+ where: activeDeploymentWhere(game2.id, "game"),
27727
+ columns: { resources: true }
27728
+ });
27729
+ if (!gameDeployment) {
27730
+ throw new ValidationError("Deploy the game before its dashboard — the dashboard attaches to the game deployment");
27731
+ }
27732
+ setAttributes({
27733
+ "app.deploy.type": "dashboard",
27734
+ "app.deploy.deployment_id": deploymentId,
27735
+ "app.deploy.code_size": contract.code.length,
27736
+ "app.deploy.compatibility_date": request.compatibilityDate ?? CLOUDFLARE_COMPATIBILITY_DATE,
27737
+ "app.deploy.compatibility_flag_count": request.compatibilityFlags?.length ?? 0
27738
+ });
27739
+ yield { type: "status", data: { message: "Fetching temporary files" } };
27740
+ const [{ tempDir, assetsPath }, platformBaseUrl, dashboardActive] = await Promise.all([
27741
+ this.fetchAndExtractFrontendAssets(slug, game2.id, contract.uploadToken, contract.uploadDeps, contract.extractZip),
27742
+ this.resolvePlatformBaseUrl(),
27743
+ db2.query.gameDeployments.findFirst({
27744
+ where: activeDeploymentWhere(game2.id, "dashboard"),
27745
+ columns: { resources: true }
27746
+ })
27747
+ ]);
27748
+ yield { type: "status", data: { message: "Extracting assets" } };
27749
+ const theme = readDashboardTheme(request.config);
27750
+ const env = {
27751
+ GAME_ID: game2.id,
27752
+ GAME_SLUG: slug,
27753
+ GAME_NAME: game2.displayName,
27754
+ ...game2.metadata?.emoji && { GAME_EMOJI: game2.metadata.emoji },
27755
+ ...theme.primary && { DASHBOARD_THEME_PRIMARY: theme.primary },
27756
+ ...theme.secondary && { DASHBOARD_THEME_SECONDARY: theme.secondary },
27757
+ PLAYCADEMY_BASE_URL: platformBaseUrl,
27758
+ PLAYCADEMY_PLATFORM_SERVICE_JWKS: this.deps.config.platformServiceJwt?.publicJwks
27759
+ };
27760
+ const gameResources = gameDeployment.resources;
27761
+ const bindings = {
27762
+ d1: gameResources?.d1?.map((database) => database.name) ?? [],
27763
+ kv: gameResources?.kv?.map((namespace) => namespace.name) ?? [],
27764
+ r2: gameResources?.r2?.filter((bucket) => bucket.kind !== "assets").map((bucket) => bucket.name) ?? []
27765
+ };
27766
+ const existingResources = {
27767
+ ...dashboardActive?.resources,
27768
+ d1: gameResources?.d1,
27769
+ kv: gameResources?.kv,
27770
+ r2: gameResources?.r2
27771
+ };
27772
+ yield { type: "status", data: { message: "Deploying dashboard" } };
27773
+ const result = await this.deployToCloudflare({
27774
+ deploymentId,
27775
+ code: contract.code,
27776
+ env,
27777
+ tempDir,
27778
+ options: {
27779
+ bindings,
27780
+ compatibilityDate: request.compatibilityDate ?? CLOUDFLARE_COMPATIBILITY_DATE,
27781
+ compatibilityFlags: request.compatibilityFlags,
27782
+ existingResources,
27783
+ assetsPath,
27784
+ keepAssets: false,
27785
+ assetsConfig: { run_worker_first: true }
27274
27786
  }
27275
- apiKey = await this.regenerateApiKey(user, slug, existingKey.id, keyName);
27787
+ });
27788
+ yield { type: "status", data: { message: "Finalizing deployment" } };
27789
+ await withSpan("deploy.configure_worker_secrets", async () => {
27790
+ const existingSecrets = await this.listWorkerSecretNames(result.deploymentId);
27791
+ await this.ensureWorkerApiKeyOnWorker(user, DeployService.dashboardWorkerKeySpec(slug), result.deploymentId, existingSecrets);
27792
+ await this.ensureDashboardSessionSecret(result.deploymentId, existingSecrets, Boolean(dashboardActive));
27793
+ });
27794
+ const codeHash = await generateDeploymentHash(contract.code);
27795
+ await this.saveDeployment({
27796
+ gameId: game2.id,
27797
+ deploymentId: result.deploymentId,
27798
+ url: result.url,
27799
+ codeHash,
27800
+ resources: result.resources,
27801
+ target: "dashboard"
27802
+ });
27803
+ setAttribute("app.deploy.code_hash", codeHash);
27804
+ try {
27805
+ await withSpan("deploy.send_alert", () => this.deps.alerts.notifyDashboardDeployment({
27806
+ slug,
27807
+ displayName: game2.displayName,
27808
+ url: result.url,
27809
+ developer: { id: user.id, email: user.email }
27810
+ }));
27811
+ } catch (error) {
27812
+ setAttribute("app.alerts.delivery", "failed");
27813
+ setAttribute("app.alerts.delivery_error", errorMessage(error));
27814
+ setAttribute("app.alerts.type", "dashboard_deployment");
27276
27815
  }
27277
- await cf.setSecrets(deploymentId, { PLAYCADEMY_API_KEY: apiKey });
27816
+ yield { type: "complete", data: game2 };
27278
27817
  }
27279
- async ensureQueueIngressSecretOnWorker(slug, deploymentId) {
27280
- const secret = this.deps.config.queueIngressSecret;
27281
- if (!secret) {
27282
- return;
27818
+ validateGameRequest(request) {
27819
+ const hasBackend = Boolean(request.code);
27820
+ const hasFrontend = Boolean(request.uploadToken);
27821
+ const hasMetadata = Boolean(request.metadata);
27822
+ setAttributes({
27823
+ "app.deploy.has_backend": hasBackend,
27824
+ "app.deploy.has_frontend": hasFrontend,
27825
+ "app.deploy.has_metadata": hasMetadata,
27826
+ "app.deploy.type": DeployService.classifyGameDeployType({
27827
+ hasBackend,
27828
+ hasFrontend,
27829
+ hasMetadata
27830
+ }),
27831
+ "app.deploy.code_size": request.code?.length ?? 0,
27832
+ "app.deploy.compatibility_date": request.compatibilityDate ?? CLOUDFLARE_COMPATIBILITY_DATE,
27833
+ "app.deploy.compatibility_flag_count": request.compatibilityFlags?.length ?? 0,
27834
+ "app.deploy.has_schema": Boolean(request.schema)
27835
+ });
27836
+ if (!hasBackend && !hasFrontend && !hasMetadata) {
27837
+ throw new ValidationError("Must provide at least one of: uploadToken (frontend), code (backend), or metadata");
27283
27838
  }
27284
- const cf = this.getCloudflare();
27285
- await cf.setSecrets(deploymentId, { QUEUE_INGRESS_SECRET: secret });
27839
+ if (!this.deps.config.baseUrl) {
27840
+ throw new ValidationError("baseUrl is not configured");
27841
+ }
27842
+ return { hasBackend, hasFrontend, hasMetadata };
27286
27843
  }
27287
- async fetchAndExtractFrontendAssets(slug, gameId, uploadToken, uploadDeps, extractZip) {
27288
- const frontendZip = await withSpan("deploy.fetch_temporary_files", () => uploadDeps.getObjectAsByteArray(uploadToken));
27289
- if (!frontendZip || frontendZip.length === 0) {
27290
- throw new ValidationError("Uploaded file is empty or not found");
27844
+ validateDashboardRequest(request, uploadDeps, extractZip) {
27845
+ if (!request.code || !request.uploadToken) {
27846
+ throw new ValidationError("Dashboard deployments require both worker code and an asset upload");
27291
27847
  }
27292
- setAttribute("app.deploy.asset_upload_size", frontendZip.length);
27293
- const os2 = await import("os");
27294
- const path = await import("path");
27295
- const tempDir = path.join(os2.tmpdir(), `playcademy-deploy-${gameId}-${Date.now()}`);
27296
- const assetsPath = path.join(tempDir, "dist");
27297
- await withSpan("deploy.extract_assets", () => extractZip(frontendZip, assetsPath));
27298
- uploadDeps.deleteObject(uploadToken).catch(catchAttrs("deploy.temp_cleanup"));
27299
- return { frontendZip, tempDir, assetsPath };
27848
+ if (request.metadata) {
27849
+ throw new ValidationError("Dashboard deployments cannot update game metadata");
27850
+ }
27851
+ if (!uploadDeps || !extractZip) {
27852
+ throw new ValidationError("Upload dependencies not configured for frontend deployment");
27853
+ }
27854
+ if (!this.deps.config.baseUrl) {
27855
+ throw new ValidationError("baseUrl is not configured");
27856
+ }
27857
+ return { code: request.code, uploadToken: request.uploadToken, uploadDeps, extractZip };
27858
+ }
27859
+ static classifyGameDeployType(flags2) {
27860
+ if (flags2.hasBackend && flags2.hasFrontend) {
27861
+ return "full_stack";
27862
+ }
27863
+ if (flags2.hasFrontend) {
27864
+ return "frontend_only";
27865
+ }
27866
+ if (flags2.hasBackend) {
27867
+ return "backend_only";
27868
+ }
27869
+ return "metadata_only";
27870
+ }
27871
+ mapGameBindingsToOptions(deploymentId, bindings, schema2) {
27872
+ if (!bindings && !schema2) {
27873
+ return;
27874
+ }
27875
+ const workerBindings = {};
27876
+ if (bindings?.database) {
27877
+ workerBindings.d1 = [deploymentId];
27878
+ }
27879
+ if (bindings?.keyValue) {
27880
+ workerBindings.kv = [deploymentId];
27881
+ }
27882
+ if (bindings?.bucket) {
27883
+ workerBindings.r2 = [deploymentId];
27884
+ }
27885
+ if (bindings?.queues) {
27886
+ let toQueueName = function(queueKey) {
27887
+ return `${QUEUE_NAME_PREFIX}-${deploymentId}--${queueKey}`;
27888
+ };
27889
+ const queueNameByKey = new Map;
27890
+ for (const queueKey of Object.keys(bindings.queues)) {
27891
+ queueNameByKey.set(queueKey, toQueueName(queueKey));
27892
+ }
27893
+ workerBindings.queues = Object.entries(bindings.queues).map(([queueKey, queueConfig]) => {
27894
+ const config2 = queueConfig === true ? undefined : queueConfig;
27895
+ const deadLetterQueue = config2?.deadLetterQueue && queueNameByKey.get(config2.deadLetterQueue) ? queueNameByKey.get(config2.deadLetterQueue) : undefined;
27896
+ return {
27897
+ bindingName: toBindingName(queueKey),
27898
+ queueName: toQueueName(queueKey),
27899
+ settings: config2 ? {
27900
+ maxBatchSize: config2.maxBatchSize,
27901
+ maxRetries: config2.maxRetries,
27902
+ maxBatchTimeout: config2.maxBatchTimeout,
27903
+ maxConcurrency: config2.maxConcurrency,
27904
+ retryDelay: config2.retryDelay
27905
+ } : undefined,
27906
+ deadLetterQueue
27907
+ };
27908
+ });
27909
+ }
27910
+ const hasBindings = workerBindings.d1?.length || workerBindings.kv?.length || workerBindings.r2?.length || workerBindings.queues?.length;
27911
+ return {
27912
+ ...hasBindings && { bindings: workerBindings },
27913
+ ...schema2 && { schema: schema2 }
27914
+ };
27915
+ }
27916
+ static countDeadLetterQueues(bindings) {
27917
+ return bindings?.queues?.filter((queue) => Boolean(queue.deadLetterQueue)).length ?? 0;
27300
27918
  }
27301
27919
  async cleanupOrphanD1Databases(cf, d1Names, slug, gameId) {
27302
27920
  const hasAnyPriorDeployment = await this.deps.db.query.gameDeployments.findFirst({
27303
- where: eq(gameDeployments.gameId, gameId),
27921
+ where: and(eq(gameDeployments.gameId, gameId), eq(gameDeployments.target, "game")),
27304
27922
  columns: { id: true }
27305
27923
  });
27306
27924
  if (hasAnyPriorDeployment) {
@@ -27335,33 +27953,7 @@ class DeployService {
27335
27953
  }
27336
27954
  await this.deps.db.update(games).set(updates).where(eq(games.id, gameId));
27337
27955
  }
27338
- validateDeployRequest(request) {
27339
- const hasBackend = Boolean(request.code);
27340
- const hasFrontend = Boolean(request.uploadToken);
27341
- const hasMetadata = Boolean(request.metadata);
27342
- setAttributes({
27343
- "app.deploy.has_backend": hasBackend,
27344
- "app.deploy.has_frontend": hasFrontend,
27345
- "app.deploy.has_metadata": hasMetadata,
27346
- "app.deploy.type": DeployService.classifyDeployType({
27347
- hasBackend,
27348
- hasFrontend,
27349
- hasMetadata
27350
- }),
27351
- "app.deploy.code_size": request.code?.length ?? 0,
27352
- "app.deploy.compatibility_date": request.compatibilityDate ?? CLOUDFLARE_COMPATIBILITY_DATE,
27353
- "app.deploy.compatibility_flag_count": request.compatibilityFlags?.length ?? 0,
27354
- "app.deploy.has_schema": Boolean(request.schema)
27355
- });
27356
- if (!hasBackend && !hasFrontend && !hasMetadata) {
27357
- throw new ValidationError("Must provide at least one of: uploadToken (frontend), code (backend), or metadata");
27358
- }
27359
- if (!this.deps.config.baseUrl) {
27360
- throw new ValidationError("baseUrl is not configured");
27361
- }
27362
- return { hasBackend, hasFrontend, hasMetadata };
27363
- }
27364
- async finalizeDeployment({
27956
+ async finalizeGameDeployment({
27365
27957
  game: game2,
27366
27958
  slug,
27367
27959
  deploymentId,
@@ -27373,10 +27965,17 @@ class DeployService {
27373
27965
  const { hasBackend, hasFrontend, hasMetadata } = flags2;
27374
27966
  const db2 = this.deps.db;
27375
27967
  const codeHash = hasBackend ? await generateDeploymentHash(request.code) : null;
27376
- await this.saveDeployment(game2.id, result.deploymentId, result.url, codeHash, result.resources);
27968
+ await this.saveDeployment({
27969
+ gameId: game2.id,
27970
+ deploymentId: result.deploymentId,
27971
+ url: result.url,
27972
+ codeHash,
27973
+ resources: result.resources,
27974
+ target: "game"
27975
+ });
27377
27976
  if (hasBackend) {
27378
27977
  await withSpan("deploy.configure_worker_secrets", async () => {
27379
- await this.ensureApiKeyOnWorker(user, slug, result.deploymentId);
27978
+ await this.ensureWorkerApiKeyOnWorker(user, DeployService.gameWorkerKeySpec(slug), result.deploymentId);
27380
27979
  await this.ensureQueueIngressSecretOnWorker(slug, result.deploymentId);
27381
27980
  });
27382
27981
  }
@@ -27409,169 +28008,232 @@ class DeployService {
27409
28008
  }
27410
28009
  return updatedGame;
27411
28010
  }
27412
- async* deploy(slug, request, user, uploadDeps, extractZip) {
27413
- const cf = this.getCloudflare();
27414
- const db2 = this.deps.db;
27415
- const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
27416
- const flags2 = this.validateDeployRequest(request);
27417
- const { hasBackend, hasFrontend } = flags2;
27418
- const deploymentId = getDeploymentId(slug, this.deps.config.sstStage);
27419
- let frontendAssetsPath;
27420
- let tempDir;
27421
- if (hasFrontend) {
27422
- if (!uploadDeps || !extractZip) {
27423
- throw new ValidationError("Upload dependencies not configured for frontend deployment");
27424
- }
27425
- yield { type: "status", data: { message: "Fetching temporary files" } };
27426
- const extracted = await this.fetchAndExtractFrontendAssets(slug, game2.id, request.uploadToken, uploadDeps, extractZip);
27427
- tempDir = extracted.tempDir;
27428
- frontendAssetsPath = extracted.assetsPath;
27429
- yield { type: "status", data: { message: "Extracting assets" } };
27430
- }
27431
- let platformBaseUrl = this.deps.config.baseUrl;
27432
- if (this.deps.config.isLocal) {
27433
- try {
27434
- platformBaseUrl = await getTunnelUrl();
27435
- } catch {
27436
- setAttributes({
27437
- "app.deploy.tunnel_available": false,
27438
- "app.deploy.failure_kind": "local_tunnel_unavailable"
27439
- });
27440
- throw new ValidationError("Local tunnel is not running. Ensure cloudflared is installed (`brew install cloudflared`) and the tunnel DevCommand started successfully.");
27441
- }
27442
- }
27443
- const env = {
27444
- GAME_ID: game2.id,
27445
- PLAYCADEMY_BASE_URL: platformBaseUrl,
27446
- PLAYCADEMY_PLATFORM_SERVICE_JWKS: this.deps.config.platformServiceJwt?.publicJwks
28011
+ static gameWorkerKeySpec(slug) {
28012
+ return {
28013
+ keyName: getGameWorkerApiKeyName(slug),
28014
+ permissions: { games: [`read:${slug}`, `write:${slug}`] },
28015
+ lookup: "owner-and-name"
27447
28016
  };
27448
- yield {
27449
- type: "status",
27450
- data: { message: hasBackend ? "Deploying backend code" : "Deploying to platform" }
28017
+ }
28018
+ static dashboardWorkerKeySpec(slug) {
28019
+ return {
28020
+ keyName: getDashboardWorkerApiKeyName(slug),
28021
+ permissions: {
28022
+ games: [`read:${slug}`],
28023
+ [DASHBOARD_PERMISSION_NAMESPACE]: [dashboardCredentialScope(slug)]
28024
+ },
28025
+ rateLimit: { maxRequests: 300, timeWindowMs: 60000 },
28026
+ lookup: "name",
28027
+ isCurrent: (permissionsJson) => DeployService.hasDashboardCredentialScope(permissionsJson, slug)
27451
28028
  };
27452
- const keepAssets = hasBackend && !hasFrontend;
27453
- const deploymentOptions = this.mapBindingsToOptions(deploymentId, request.bindings, request.schema);
27454
- const bindings = deploymentOptions?.bindings;
27455
- setAttributes({
27456
- "app.deploy.has_d1": Boolean(bindings?.d1?.length),
27457
- "app.deploy.has_kv": Boolean(bindings?.kv?.length),
27458
- "app.deploy.has_r2": Boolean(bindings?.r2?.length),
27459
- "app.deploy.queue_count": bindings?.queues?.length ?? 0,
27460
- "app.deploy.dead_letter_queue_count": DeployService.countDeadLetterQueues(bindings)
27461
- });
27462
- const activeDeployment = await db2.query.gameDeployments.findFirst({
27463
- where: and(eq(gameDeployments.gameId, game2.id), eq(gameDeployments.isActive, true)),
27464
- columns: { resources: true }
27465
- });
27466
- if (deploymentOptions?.bindings?.d1?.length) {
27467
- await this.cleanupOrphanD1Databases(cf, deploymentOptions.bindings.d1, slug, game2.id);
28029
+ }
28030
+ static hasDashboardCredentialScope(permissionsJson, slug) {
28031
+ if (!permissionsJson) {
28032
+ return false;
27468
28033
  }
27469
- let result;
27470
28034
  try {
27471
- result = await withSpan("deploy.cloudflare", () => cf.deploy(deploymentId, request.code, env, {
27472
- ...deploymentOptions,
27473
- compatibilityDate: request.compatibilityDate ?? CLOUDFLARE_COMPATIBILITY_DATE,
27474
- compatibilityFlags: request.compatibilityFlags,
27475
- existingResources: activeDeployment?.resources ?? undefined,
27476
- assetsPath: frontendAssetsPath,
27477
- keepAssets
27478
- }));
27479
- } finally {
27480
- if (tempDir) {
27481
- const fs2 = await import("fs/promises");
27482
- fs2.rm(tempDir, { recursive: true, force: true }).catch(catchAttrs("deploy.temp_cleanup"));
28035
+ const parsed = JSON.parse(permissionsJson);
28036
+ return dashboardCredentialSlugs(parsed).includes(slug);
28037
+ } catch {
28038
+ return false;
28039
+ }
28040
+ }
28041
+ async ensureWorkerApiKeyOnWorker(user, spec, deploymentId, existingSecrets) {
28042
+ const cf = this.getCloudflare();
28043
+ const existingKey = await this.deps.db.query.apikey.findFirst({
28044
+ where: spec.lookup === "owner-and-name" ? and(eq(apikey.userId, user.id), eq(apikey.name, spec.keyName)) : eq(apikey.name, spec.keyName),
28045
+ columns: { id: true, permissions: true }
28046
+ });
28047
+ let apiKey;
28048
+ if (!existingKey) {
28049
+ apiKey = await this.createApiKey(user, spec);
28050
+ } else {
28051
+ const current = spec.isCurrent?.(existingKey.permissions) ?? true;
28052
+ const workerHasKey = existingSecrets ? existingSecrets.includes("PLAYCADEMY_API_KEY") : await this.workerHasSecret(deploymentId, "PLAYCADEMY_API_KEY");
28053
+ if (current && workerHasKey) {
28054
+ setAttribute("app.deploy.api_key_outcome", "already_set");
28055
+ return;
27483
28056
  }
28057
+ apiKey = await this.regenerateApiKey(user, existingKey.id, spec);
27484
28058
  }
27485
- yield { type: "status", data: { message: "Finalizing deployment" } };
27486
- const updatedGame = await this.finalizeDeployment({
27487
- game: game2,
27488
- slug,
27489
- deploymentId,
27490
- result,
27491
- request,
27492
- user,
27493
- flags: flags2
28059
+ await cf.setSecrets(deploymentId, { PLAYCADEMY_API_KEY: apiKey });
28060
+ }
28061
+ async createApiKey(user, spec) {
28062
+ const { key: apiKey } = await this.deps.createAuthApiKey({
28063
+ userId: user.id,
28064
+ name: spec.keyName,
28065
+ expiresIn: null,
28066
+ permissions: spec.permissions,
28067
+ ...spec.rateLimit ? {
28068
+ rateLimitEnabled: true,
28069
+ rateLimitMax: spec.rateLimit.maxRequests,
28070
+ rateLimitTimeWindow: spec.rateLimit.timeWindowMs
28071
+ } : { rateLimitEnabled: false }
27494
28072
  });
27495
- yield { type: "complete", data: updatedGame };
28073
+ setAttribute("app.deploy.api_key_outcome", "created");
28074
+ return apiKey;
27496
28075
  }
27497
- mapBindingsToOptions(deploymentId, bindings, schema2) {
27498
- if (!bindings && !schema2) {
28076
+ async regenerateApiKey(user, existingKeyId, spec) {
28077
+ setAttribute("app.deploy.api_key_outcome", "regenerated");
28078
+ try {
28079
+ await this.deps.deleteAuthApiKey(existingKeyId);
28080
+ } catch (error) {
28081
+ addEvent("deploy.api_key_revoke_failed", {
28082
+ "exception.type": errorType(error),
28083
+ "app.error.message": errorMessage(error),
28084
+ "app.deploy.old_key_id": existingKeyId
28085
+ });
28086
+ }
28087
+ return this.createApiKey(user, spec);
28088
+ }
28089
+ async listWorkerSecretNames(deploymentId) {
28090
+ try {
28091
+ return await this.getCloudflare().listSecrets(deploymentId);
28092
+ } catch (error) {
28093
+ addEvent("deploy.worker_secrets_check_failed", {
28094
+ "exception.type": errorType(error),
28095
+ "app.error.message": errorMessage(error)
28096
+ });
28097
+ return null;
28098
+ }
28099
+ }
28100
+ async workerHasSecret(deploymentId, secretName) {
28101
+ const workerSecrets = await this.listWorkerSecretNames(deploymentId);
28102
+ return Boolean(workerSecrets?.includes(secretName));
28103
+ }
28104
+ async ensureQueueIngressSecretOnWorker(slug, deploymentId) {
28105
+ const secret = this.deps.config.queueIngressSecret;
28106
+ if (!secret) {
27499
28107
  return;
27500
28108
  }
27501
- const workerBindings = {};
27502
- if (bindings?.database) {
27503
- workerBindings.d1 = [deploymentId];
28109
+ const cf = this.getCloudflare();
28110
+ await cf.setSecrets(deploymentId, { QUEUE_INGRESS_SECRET: secret });
28111
+ }
28112
+ async ensureDashboardSessionSecret(deploymentId, existingSecrets, hasPriorDeployment) {
28113
+ if (existingSecrets === null && hasPriorDeployment) {
28114
+ setAttribute("app.deploy.session_secret_outcome", "check_failed_kept");
28115
+ return;
27504
28116
  }
27505
- if (bindings?.keyValue) {
27506
- workerBindings.kv = [deploymentId];
28117
+ if (existingSecrets?.includes("DASHBOARD_SESSION_SECRET")) {
28118
+ setAttribute("app.deploy.session_secret_outcome", "already_set");
28119
+ return;
27507
28120
  }
27508
- if (bindings?.bucket) {
27509
- workerBindings.r2 = [deploymentId];
28121
+ const secret = await generateSecureRandomString(64);
28122
+ await this.getCloudflare().setSecrets(deploymentId, { DASHBOARD_SESSION_SECRET: secret });
28123
+ setAttribute("app.deploy.session_secret_outcome", "created");
28124
+ }
28125
+ async rotateDashboardSessionSecret(slug, user) {
28126
+ const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
28127
+ const deployment = await this.deps.db.query.gameDeployments.findFirst({
28128
+ where: activeDeploymentWhere(game2.id, "dashboard"),
28129
+ columns: { deploymentId: true }
28130
+ });
28131
+ if (!deployment) {
28132
+ await sweepDashboardWorkerKeys(this.deps.deleteApiKeysByName, slug);
28133
+ throw new NotFoundError("Dashboard deployment", slug);
27510
28134
  }
27511
- if (bindings?.queues) {
27512
- let toQueueName = function(queueKey) {
27513
- return `${QUEUE_NAME_PREFIX}-${deploymentId}--${queueKey}`;
27514
- };
27515
- const queueNameByKey = new Map;
27516
- for (const queueKey of Object.keys(bindings.queues)) {
27517
- queueNameByKey.set(queueKey, toQueueName(queueKey));
27518
- }
27519
- workerBindings.queues = Object.entries(bindings.queues).map(([queueKey, queueConfig]) => {
27520
- const config2 = queueConfig === true ? undefined : queueConfig;
27521
- const deadLetterQueue = config2?.deadLetterQueue && queueNameByKey.get(config2.deadLetterQueue) ? queueNameByKey.get(config2.deadLetterQueue) : undefined;
27522
- return {
27523
- bindingName: toBindingName(queueKey),
27524
- queueName: toQueueName(queueKey),
27525
- settings: config2 ? {
27526
- maxBatchSize: config2.maxBatchSize,
27527
- maxRetries: config2.maxRetries,
27528
- maxBatchTimeout: config2.maxBatchTimeout,
27529
- maxConcurrency: config2.maxConcurrency,
27530
- retryDelay: config2.retryDelay
27531
- } : undefined,
27532
- deadLetterQueue
27533
- };
28135
+ const secret = await generateSecureRandomString(64);
28136
+ await this.getCloudflare().setSecrets(deployment.deploymentId, {
28137
+ DASHBOARD_SESSION_SECRET: secret
28138
+ });
28139
+ setAttribute("app.deploy.session_secret_outcome", "rotated");
28140
+ }
28141
+ async removeDashboard(slug, user) {
28142
+ const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
28143
+ const db2 = this.deps.db;
28144
+ const deployment = await db2.query.gameDeployments.findFirst({
28145
+ where: activeDeploymentWhere(game2.id, "dashboard"),
28146
+ columns: { deploymentId: true, provider: true, resources: true }
28147
+ });
28148
+ if (!deployment) {
28149
+ await sweepDashboardWorkerKeys(this.deps.deleteApiKeysByName, slug);
28150
+ throw new NotFoundError("Dashboard deployment", slug);
28151
+ }
28152
+ const assetBuckets = deployment.resources?.r2?.filter((bucket) => bucket.kind === "assets") ?? [];
28153
+ await this.getCloudflare().delete(deployment.deploymentId, {
28154
+ deleteBindings: assetBuckets.length > 0,
28155
+ resources: assetBuckets.length > 0 ? { r2: assetBuckets } : undefined
28156
+ });
28157
+ await sweepDashboardWorkerKeys(this.deps.deleteApiKeysByName, slug);
28158
+ await db2.delete(gameDeployments).where(and(eq(gameDeployments.gameId, game2.id), eq(gameDeployments.target, "dashboard")));
28159
+ setAttribute("app.deploy.dashboard_removed", true);
28160
+ await withSpan("deploy.send_alert", () => this.deps.alerts.notifyDashboardRemoval({
28161
+ slug,
28162
+ displayName: game2.displayName,
28163
+ developer: { id: user.id, email: user.email }
28164
+ })).catch(catchAttrs("alerts.delivery", { "app.alerts.type": "dashboard_removal" }));
28165
+ }
28166
+ async fetchAndExtractFrontendAssets(slug, gameId, uploadToken, uploadDeps, extractZip) {
28167
+ const frontendZip = await withSpan("deploy.fetch_temporary_files", () => uploadDeps.getObjectAsByteArray(uploadToken));
28168
+ if (!frontendZip || frontendZip.length === 0) {
28169
+ throw new ValidationError("Uploaded file is empty or not found");
28170
+ }
28171
+ setAttribute("app.deploy.asset_upload_size", frontendZip.length);
28172
+ const os2 = await import("os");
28173
+ const path = await import("path");
28174
+ const tempDir = path.join(os2.tmpdir(), `playcademy-deploy-${gameId}-${Date.now()}`);
28175
+ const assetsPath = path.join(tempDir, "dist");
28176
+ await withSpan("deploy.extract_assets", () => extractZip(frontendZip, assetsPath));
28177
+ uploadDeps.deleteObject(uploadToken).catch(catchAttrs("deploy.temp_cleanup"));
28178
+ return { frontendZip, tempDir, assetsPath };
28179
+ }
28180
+ async resolvePlatformBaseUrl() {
28181
+ if (!this.deps.config.isLocal) {
28182
+ return this.deps.config.baseUrl;
28183
+ }
28184
+ try {
28185
+ return await getTunnelUrl();
28186
+ } catch {
28187
+ setAttributes({
28188
+ "app.deploy.tunnel_available": false,
28189
+ "app.deploy.failure_kind": "local_tunnel_unavailable"
27534
28190
  });
28191
+ throw new ValidationError("Local tunnel is not running. Ensure cloudflared is installed (`brew install cloudflared`) and the tunnel DevCommand started successfully.");
27535
28192
  }
27536
- const hasBindings = workerBindings.d1?.length || workerBindings.kv?.length || workerBindings.r2?.length || workerBindings.queues?.length;
27537
- return {
27538
- ...hasBindings && { bindings: workerBindings },
27539
- ...schema2 && { schema: schema2 }
27540
- };
27541
28193
  }
27542
- async notifyDeploymentFailure(slug, displayName, error, developer) {
27543
- await this.deps.alerts.notifyDeploymentFailure({
27544
- slug,
27545
- displayName,
27546
- error,
27547
- developer
27548
- }).catch(catchAttrs("alerts.delivery", { "app.alerts.type": "deployment_failure" }));
28194
+ async deployToCloudflare(args2) {
28195
+ const cf = this.getCloudflare();
28196
+ try {
28197
+ return await withSpan("deploy.cloudflare", () => cf.deploy(args2.deploymentId, args2.code, args2.env, args2.options));
28198
+ } finally {
28199
+ if (args2.tempDir) {
28200
+ const fs2 = await import("fs/promises");
28201
+ fs2.rm(args2.tempDir, { recursive: true, force: true }).catch(catchAttrs("deploy.temp_cleanup"));
28202
+ }
28203
+ }
27549
28204
  }
27550
- async saveDeployment(gameId, deploymentId, url, codeHash, resources) {
28205
+ async saveDeployment(record) {
27551
28206
  const db2 = this.deps.db;
27552
28207
  await db2.transaction(async (tx) => {
27553
- await tx.update(gameDeployments).set({ isActive: false }).where(eq(gameDeployments.gameId, gameId));
28208
+ await tx.update(gameDeployments).set({ isActive: false }).where(and(eq(gameDeployments.gameId, record.gameId), eq(gameDeployments.target, record.target)));
27554
28209
  await tx.insert(gameDeployments).values({
27555
- gameId,
27556
- deploymentId,
28210
+ gameId: record.gameId,
28211
+ deploymentId: record.deploymentId,
27557
28212
  provider: "cloudflare",
27558
- url,
27559
- codeHash,
27560
- resources,
28213
+ target: record.target,
28214
+ url: record.url,
28215
+ codeHash: record.codeHash,
28216
+ resources: record.resources,
27561
28217
  isActive: true
27562
28218
  });
27563
28219
  });
27564
28220
  }
28221
+ async notifyDeploymentFailure(failure) {
28222
+ await this.deps.alerts.notifyDeploymentFailure(failure).catch(catchAttrs("alerts.delivery", { "app.alerts.type": "deployment_failure" }));
28223
+ }
27565
28224
  }
27566
28225
  var init_deploy_service = __esm(() => {
27567
28226
  init_drizzle_orm();
27568
28227
  init_playcademy();
27569
28228
  init_src();
28229
+ init_helpers_index();
27570
28230
  init_tables_index();
27571
28231
  init_spans();
27572
28232
  init_tunnel();
27573
28233
  init_errors();
28234
+ init_dashboard_util();
27574
28235
  init_deployment_util();
28236
+ init_worker_keys_util();
27575
28237
  });
27576
28238
 
27577
28239
  // ../api-core/src/services/developer.service.ts
@@ -27816,20 +28478,6 @@ var init_game_member_service = __esm(() => {
27816
28478
  init_spans();
27817
28479
  init_errors();
27818
28480
  });
27819
- // ../data/src/domains/timeback/helpers.ts
27820
- function isActiveGameTimebackIntegrationStatus(statusColumn = gameTimebackIntegrations.status) {
27821
- return sql`${statusColumn} IS DISTINCT FROM ${DEACTIVATED_GAME_TIMEBACK_INTEGRATION_STATUS}`;
27822
- }
27823
- var ACTIVE_GAME_TIMEBACK_INTEGRATION_STATUS = "active", DEACTIVATED_GAME_TIMEBACK_INTEGRATION_STATUS = "deactivated";
27824
- var init_helpers2 = __esm(() => {
27825
- init_drizzle_orm();
27826
- init_table7();
27827
- });
27828
-
27829
- // ../data/src/helpers.index.ts
27830
- var init_helpers_index = __esm(() => {
27831
- init_helpers2();
27832
- });
27833
28481
 
27834
28482
  // ../utils/src/fns.ts
27835
28483
  function sleep(ms) {
@@ -28273,6 +28921,7 @@ var init_game_service = __esm(() => {
28273
28921
  init_errors();
28274
28922
  init_deployment_util();
28275
28923
  init_timeback_util();
28924
+ init_worker_keys_util();
28276
28925
  inFlightManifestFetches = new Map;
28277
28926
  GameService = class GameService {
28278
28927
  deps;
@@ -28459,7 +29108,7 @@ var init_game_service = __esm(() => {
28459
29108
  GameService.recordGameShape(game2);
28460
29109
  return game2;
28461
29110
  }
28462
- async getBySlug(slug, caller) {
29111
+ async getBySlug(slug, caller, options) {
28463
29112
  const db2 = this.deps.db;
28464
29113
  const game2 = await db2.query.games.findFirst({
28465
29114
  where: eq(games.slug, slug)
@@ -28467,7 +29116,9 @@ var init_game_service = __esm(() => {
28467
29116
  if (!game2) {
28468
29117
  throw new NotFoundError("Game", slug);
28469
29118
  }
28470
- await this.enforceVisibility(game2, caller, slug);
29119
+ if (!options?.scopeAuthorized) {
29120
+ await this.enforceVisibility(game2, caller, slug);
29121
+ }
28471
29122
  GameService.recordGameShape(game2);
28472
29123
  return game2;
28473
29124
  }
@@ -28644,6 +29295,9 @@ var init_game_service = __esm(() => {
28644
29295
  await this.validateDeveloperAccess(user, gameId);
28645
29296
  } else {
28646
29297
  this.validateDeveloperStatus(user);
29298
+ if (slug.endsWith(DASHBOARD_WORKER_SUFFIX)) {
29299
+ throw new ValidationError(`Game slugs may not end with '${DASHBOARD_WORKER_SUFFIX}' — it is reserved for dashboard workers`);
29300
+ }
28647
29301
  }
28648
29302
  const gameDataForDb = {
28649
29303
  displayName: data.displayName,
@@ -28770,15 +29424,21 @@ var init_game_service = __esm(() => {
28770
29424
  if (!gameToDelete?.slug) {
28771
29425
  throw new NotFoundError("Game", gameId);
28772
29426
  }
28773
- const activeDeployment = await db2.query.gameDeployments.findFirst({
28774
- where: and(eq(gameDeployments.gameId, gameId), eq(gameDeployments.isActive, true)),
28775
- columns: { deploymentId: true, provider: true, resources: true }
28776
- });
28777
- const customHostnames = await db2.select({
28778
- hostname: gameCustomHostnames.hostname,
28779
- cloudflareId: gameCustomHostnames.cloudflareId,
28780
- environment: gameCustomHostnames.environment
28781
- }).from(gameCustomHostnames).where(eq(gameCustomHostnames.gameId, gameId));
29427
+ const [activeDeployment, dashboardDeployment, customHostnames] = await Promise.all([
29428
+ db2.query.gameDeployments.findFirst({
29429
+ where: activeDeploymentWhere(gameId, "game"),
29430
+ columns: { deploymentId: true, provider: true, resources: true }
29431
+ }),
29432
+ db2.query.gameDeployments.findFirst({
29433
+ where: activeDeploymentWhere(gameId, "dashboard"),
29434
+ columns: { deploymentId: true, provider: true, resources: true }
29435
+ }),
29436
+ db2.select({
29437
+ hostname: gameCustomHostnames.hostname,
29438
+ cloudflareId: gameCustomHostnames.cloudflareId,
29439
+ environment: gameCustomHostnames.environment
29440
+ }).from(gameCustomHostnames).where(eq(gameCustomHostnames.gameId, gameId))
29441
+ ]);
28782
29442
  const result = await db2.delete(games).where(eq(games.id, gameId)).returning({ id: games.id });
28783
29443
  if (result.length === 0) {
28784
29444
  throw new NotFoundError("Game", gameId);
@@ -28822,6 +29482,22 @@ var init_game_service = __esm(() => {
28822
29482
  setAttribute("app.game.api_key_cleanup_error", errorMessage(error));
28823
29483
  }
28824
29484
  }
29485
+ if (dashboardDeployment?.provider === "cloudflare" && this.deps.cloudflare) {
29486
+ const dashboardAssetBuckets = dashboardDeployment.resources?.r2?.filter((bucket) => bucket.kind === "assets") ?? [];
29487
+ try {
29488
+ await this.deps.cloudflare.delete(dashboardDeployment.deploymentId, {
29489
+ deleteBindings: dashboardAssetBuckets.length > 0,
29490
+ resources: dashboardAssetBuckets.length > 0 ? { r2: dashboardAssetBuckets } : undefined
29491
+ });
29492
+ setAttribute("app.game.dashboard_cleanup", "succeeded");
29493
+ } catch (error) {
29494
+ setAttributes({
29495
+ "app.game.dashboard_cleanup": "failed",
29496
+ "app.game.dashboard_cleanup_error": errorMessage(error)
29497
+ });
29498
+ }
29499
+ }
29500
+ await sweepDashboardWorkerKeys(this.deps.deleteApiKeysByName, gameToDelete.slug);
28825
29501
  const corsOrigin = GameService.safeOrigin(gameToDelete);
28826
29502
  if (this.deps.corsKvs && corsOrigin) {
28827
29503
  setAttribute("app.cors_kvs.origin", corsOrigin);
@@ -28945,7 +29621,7 @@ class LogsService {
28945
29621
  }
28946
29622
  async generateToken(user, slug, sstStage) {
28947
29623
  await this.deps.validateDeveloperAccessBySlug(user, slug);
28948
- const workerId = getDeploymentId(slug, sstStage);
29624
+ const workerId = getGameDeploymentId(slug, sstStage);
28949
29625
  const token = await this.deps.mintLogStreamToken(user.id, workerId);
28950
29626
  setAttribute("app.logs.worker_id", workerId);
28951
29627
  return { token, workerId };
@@ -28965,7 +29641,8 @@ function createGameServices(deps) {
28965
29641
  cache,
28966
29642
  cloudflare: cloudflare2,
28967
29643
  corsKvs,
28968
- deleteApiKeyByName: auth2.deleteApiKeyByName.bind(auth2)
29644
+ deleteApiKeyByName: auth2.deleteApiKeyByName.bind(auth2),
29645
+ deleteApiKeysByName: auth2.deleteApiKeysByName.bind(auth2)
28969
29646
  });
28970
29647
  const gameMember = new GameMemberService({
28971
29648
  db: db2,
@@ -28978,6 +29655,7 @@ function createGameServices(deps) {
28978
29655
  cloudflare: cloudflare2,
28979
29656
  createAuthApiKey: auth2.createApiKey.bind(auth2),
28980
29657
  deleteAuthApiKey: auth2.deleteApiKey.bind(auth2),
29658
+ deleteApiKeysByName: auth2.deleteApiKeysByName.bind(auth2),
28981
29659
  alerts,
28982
29660
  validateDeveloperAccessBySlug: (user, slug) => game2.validateDeveloperAccessBySlug(user, slug)
28983
29661
  });
@@ -28987,14 +29665,20 @@ function createGameServices(deps) {
28987
29665
  storage,
28988
29666
  validateDeveloperAccessBySlug: (user, slug) => game2.validateDeveloperAccessBySlug(user, slug),
28989
29667
  runDeploy: (slug, request, user, uploadDeps, extractZip) => deploy.deploy(slug, request, user, uploadDeps, extractZip),
28990
- notifyDeploymentFailure: (slug, displayName, error, developerInfo) => deploy.notifyDeploymentFailure(slug, displayName, error, developerInfo)
29668
+ notifyDeploymentFailure: (failure) => deploy.notifyDeploymentFailure(failure)
28991
29669
  });
28992
29670
  const logs = new LogsService({
28993
29671
  mintLogStreamToken: auth2.mintLogStreamToken.bind(auth2),
28994
29672
  validateDeveloperAccessBySlug: (user, slug) => game2.validateDeveloperAccessBySlug(user, slug)
28995
29673
  });
29674
+ const dashboard2 = new DashboardService({
29675
+ db: db2,
29676
+ hashPassword: auth2.hashPassword.bind(auth2),
29677
+ verifyPassword: auth2.verifyPassword.bind(auth2),
29678
+ validateDeveloperAccessBySlug: (user, slug) => game2.validateDeveloperAccessBySlug(user, slug)
29679
+ });
28996
29680
  return {
28997
- services: { game: game2, gameMember, developer, deploy, deployJobs, logs },
29681
+ services: { game: game2, gameMember, developer, deploy, deployJobs, logs, dashboard: dashboard2 },
28998
29682
  validators: {
28999
29683
  validateDeveloperAccessBySlug: (user, slug) => game2.validateDeveloperAccessBySlug(user, slug),
29000
29684
  validateDeveloperAccess: (user, gameId) => game2.validateDeveloperAccess(user, gameId),
@@ -29004,6 +29688,7 @@ function createGameServices(deps) {
29004
29688
  };
29005
29689
  }
29006
29690
  var init_game2 = __esm(() => {
29691
+ init_dashboard_service();
29007
29692
  init_deploy_job_service();
29008
29693
  init_deploy_service();
29009
29694
  init_developer_service();
@@ -29188,12 +29873,25 @@ class AlertsService {
29188
29873
  embed.setFooter("Playcademy Developer Platform").setTimestamp();
29189
29874
  await this.sendAlert(discord, embed.build());
29190
29875
  }
29876
+ async notifyDashboardDeployment(dashboard2) {
29877
+ const discord = this.recordAlert("dashboard_deployment");
29878
+ if (!discord) {
29879
+ return;
29880
+ }
29881
+ const embed = new DiscordEmbedBuilder().setTitle("\uD83D\uDCCA Dashboard Deployed").setDescription(`The dashboard for **${dashboard2.displayName || dashboard2.slug}** has been deployed (**${this.getEnvironment()}**).`).setColor(DiscordColors.GREEN).addField("Slug", dashboard2.slug, true).addField("URL", dashboard2.url, false);
29882
+ if (dashboard2.developer) {
29883
+ embed.addField("Developer", dashboard2.developer.email || dashboard2.developer.id, true);
29884
+ }
29885
+ embed.setFooter("Playcademy Developer Platform").setTimestamp();
29886
+ await this.sendAlert(discord, embed.build());
29887
+ }
29191
29888
  async notifyDeploymentFailure(failure) {
29192
29889
  const discord = this.recordAlert("deployment_failure");
29193
29890
  if (!discord) {
29194
29891
  return;
29195
29892
  }
29196
- const embed = new DiscordEmbedBuilder().setTitle("❌ Deployment Failed").setDescription(`Deployment failed for **${failure.displayName || failure.slug}** (**${this.getEnvironment()}**).`).setColor(DiscordColors.RED).addField("Slug", failure.slug, true);
29893
+ const [title, subject] = failure.target === "dashboard" ? ["Dashboard Deployment Failed", "Dashboard deployment"] : ["❌ Deployment Failed", "Deployment"];
29894
+ const embed = new DiscordEmbedBuilder().setTitle(title).setDescription(`${subject} failed for **${failure.displayName || failure.slug}** (**${this.getEnvironment()}**).`).setColor(DiscordColors.RED).addField("Slug", failure.slug, true);
29197
29895
  if (failure.developer) {
29198
29896
  embed.addField("Developer", failure.developer.email || failure.developer.id, true);
29199
29897
  }
@@ -29208,6 +29906,14 @@ class AlertsService {
29208
29906
  const embed = new DiscordEmbedBuilder().setTitle("\uD83D\uDDD1️ Game Deleted").setDescription(`**${game2.displayName || game2.slug}** has been deleted (**${this.getEnvironment()}**).`).setColor(DiscordColors.ORANGE).addField("Slug", game2.slug, true).addField("Developer", game2.developer.email || game2.developer.id, true).setFooter("Playcademy Developer Platform").setTimestamp().build();
29209
29907
  await this.sendAlert(discord, embed);
29210
29908
  }
29909
+ async notifyDashboardRemoval(dashboard2) {
29910
+ const discord = this.recordAlert("dashboard_removal");
29911
+ if (!discord) {
29912
+ return;
29913
+ }
29914
+ const embed = new DiscordEmbedBuilder().setTitle("\uD83D\uDDD1️ Dashboard Removed").setDescription(`The dashboard for **${dashboard2.displayName || dashboard2.slug}** has been removed (**${this.getEnvironment()}**).`).setColor(DiscordColors.ORANGE).addField("Slug", dashboard2.slug, true).addField("Developer", dashboard2.developer.email || dashboard2.developer.id, true).setFooter("Playcademy Developer Platform").setTimestamp().build();
29915
+ await this.sendAlert(discord, embed);
29916
+ }
29211
29917
  async notifySeedFailure(failure) {
29212
29918
  const discord = this.recordAlert("seed_failure");
29213
29919
  if (!discord) {
@@ -29373,6 +30079,7 @@ class KVBackupService {
29373
30079
  async getTargets(gameSlug) {
29374
30080
  const conditions2 = [
29375
30081
  eq(gameDeployments.isActive, true),
30082
+ eq(gameDeployments.target, "game"),
29376
30083
  eq(gameDeployments.provider, "cloudflare")
29377
30084
  ];
29378
30085
  if (gameSlug) {
@@ -29599,7 +30306,7 @@ class BucketService {
29599
30306
  return extensionIndex > 0 ? fileName.slice(extensionIndex + 1).toLowerCase() : "(none)";
29600
30307
  }
29601
30308
  getBucketName(slug) {
29602
- return getDeploymentId(slug, this.deps.sstStage);
30309
+ return getGameDeploymentId(slug, this.deps.sstStage);
29603
30310
  }
29604
30311
  async listFiles(slug, user, prefix) {
29605
30312
  const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
@@ -29688,6 +30395,32 @@ class DatabaseService {
29688
30395
  }
29689
30396
  return d1;
29690
30397
  }
30398
+ async syncDashboardD1Binding(gameId, d1ResourceName, databaseId) {
30399
+ const dashboardDeployment = await this.deps.db.query.gameDeployments.findFirst({
30400
+ where: activeDeploymentWhere(gameId, "dashboard"),
30401
+ columns: { id: true, deploymentId: true, resources: true }
30402
+ });
30403
+ if (!dashboardDeployment || !this.deps.cloudflare) {
30404
+ return;
30405
+ }
30406
+ try {
30407
+ await this.deps.cloudflare.updateD1Binding(dashboardDeployment.deploymentId, databaseId);
30408
+ if (dashboardDeployment.resources?.d1?.length) {
30409
+ const updatedResources = {
30410
+ ...dashboardDeployment.resources,
30411
+ d1: dashboardDeployment.resources.d1.map((dbResource) => dbResource.name === d1ResourceName ? { ...dbResource, id: databaseId } : dbResource)
30412
+ };
30413
+ await this.deps.db.update(gameDeployments).set({ resources: updatedResources }).where(eq(gameDeployments.id, dashboardDeployment.id));
30414
+ }
30415
+ setAttribute("app.database.dashboard_binding", "updated");
30416
+ } catch (error) {
30417
+ addEvent("database.dashboard_binding_sync_failed", {
30418
+ "exception.type": errorType(error),
30419
+ "app.error.message": errorMessage(error),
30420
+ "app.deploy.deployment_id": dashboardDeployment.deploymentId
30421
+ });
30422
+ }
30423
+ }
29691
30424
  async reset(slug, user, schema2) {
29692
30425
  setAttributes({
29693
30426
  "app.database.operation": "reset",
@@ -29696,7 +30429,7 @@ class DatabaseService {
29696
30429
  });
29697
30430
  const d1 = this.getD1();
29698
30431
  const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
29699
- const deploymentId = getDeploymentId(slug, this.deps.config.sstStage);
30432
+ const deploymentId = getGameDeploymentId(slug, this.deps.config.sstStage);
29700
30433
  try {
29701
30434
  const databaseId = await d1.reset(deploymentId);
29702
30435
  setAttribute("app.database.id", databaseId);
@@ -29712,7 +30445,7 @@ class DatabaseService {
29712
30445
  setAttribute("app.database.binding", "skipped_no_provider");
29713
30446
  }
29714
30447
  const activeDeployment = await this.deps.db.query.gameDeployments.findFirst({
29715
- where: and(eq(gameDeployments.gameId, game2.id), eq(gameDeployments.isActive, true)),
30448
+ where: activeDeploymentWhere(game2.id),
29716
30449
  columns: { id: true, resources: true }
29717
30450
  });
29718
30451
  setAttribute("app.database.active_deployment_found", Boolean(activeDeployment));
@@ -29723,6 +30456,7 @@ class DatabaseService {
29723
30456
  };
29724
30457
  await this.deps.db.update(gameDeployments).set({ resources: updatedResources }).where(eq(gameDeployments.id, activeDeployment.id));
29725
30458
  }
30459
+ await this.syncDashboardD1Binding(game2.id, deploymentId, databaseId);
29726
30460
  setAttributes({
29727
30461
  "app.database.deployment_id": deploymentId,
29728
30462
  "app.database.schema_pushed": schemaPushed
@@ -29746,6 +30480,7 @@ class DatabaseService {
29746
30480
  }
29747
30481
  var init_database_service = __esm(() => {
29748
30482
  init_drizzle_orm();
30483
+ init_helpers_index();
29749
30484
  init_tables_index();
29750
30485
  init_spans();
29751
30486
  init_errors();
@@ -29989,7 +30724,7 @@ class KVService {
29989
30724
  const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
29990
30725
  const db2 = this.deps.db;
29991
30726
  const deployment = await db2.query.gameDeployments.findFirst({
29992
- where: and(eq(gameDeployments.gameId, game2.id), eq(gameDeployments.isActive, true)),
30727
+ where: activeDeploymentWhere(game2.id),
29993
30728
  columns: { resources: true }
29994
30729
  });
29995
30730
  if (!deployment?.resources?.kv?.length) {
@@ -30110,8 +30845,7 @@ class KVService {
30110
30845
  }
30111
30846
  }
30112
30847
  var init_kv_service = __esm(() => {
30113
- init_drizzle_orm();
30114
- init_tables_index();
30848
+ init_helpers_index();
30115
30849
  init_spans();
30116
30850
  init_errors();
30117
30851
  });
@@ -30128,13 +30862,13 @@ class SecretsService {
30128
30862
  }
30129
30863
  return this.deps.cloudflare;
30130
30864
  }
30131
- getDeploymentId(slug) {
30132
- return getDeploymentId(slug, this.deps.config.sstStage);
30865
+ getGameDeploymentId(slug) {
30866
+ return getGameDeploymentId(slug, this.deps.config.sstStage);
30133
30867
  }
30134
30868
  async listKeys(slug, user) {
30135
30869
  await this.deps.validateDeveloperAccessBySlug(user, slug);
30136
30870
  const cf = this.getCloudflare();
30137
- const deploymentId = this.getDeploymentId(slug);
30871
+ const deploymentId = this.getGameDeploymentId(slug);
30138
30872
  try {
30139
30873
  const allKeys = await cf.listSecrets(deploymentId);
30140
30874
  const userKeys = allKeys.filter((k) => k.startsWith(SECRETS_PREFIX)).map((k) => k.slice(SECRETS_PREFIX.length));
@@ -30160,7 +30894,7 @@ class SecretsService {
30160
30894
  async setSecrets(slug, newSecrets, user) {
30161
30895
  await this.deps.validateDeveloperAccessBySlug(user, slug);
30162
30896
  const cf = this.getCloudflare();
30163
- const deploymentId = this.getDeploymentId(slug);
30897
+ const deploymentId = this.getGameDeploymentId(slug);
30164
30898
  const secretKeys = Object.keys(newSecrets);
30165
30899
  if (secretKeys.length === 0) {
30166
30900
  throw new ValidationError("At least one secret must be provided");
@@ -30213,7 +30947,7 @@ class SecretsService {
30213
30947
  }
30214
30948
  await this.deps.validateDeveloperAccessBySlug(user, slug);
30215
30949
  const cf = this.getCloudflare();
30216
- const deploymentId = this.getDeploymentId(slug);
30950
+ const deploymentId = this.getGameDeploymentId(slug);
30217
30951
  try {
30218
30952
  const prefixedKey = `${SECRETS_PREFIX}${key}`;
30219
30953
  const existingKeys = await cf.listSecrets(deploymentId);
@@ -30250,27 +30984,7 @@ var init_secrets_service = __esm(() => {
30250
30984
  init_deployment_util();
30251
30985
  INTERNAL_SECRET_KEYS = ["PLAYCADEMY_API_KEY", "GAME_ID", "PLAYCADEMY_BASE_URL"];
30252
30986
  });
30253
-
30254
- // ../edge-play/src/constants.ts
30255
- var ASSET_ROUTE_PREFIX = "/api/assets/", ROUTES;
30256
- var init_constants3 = __esm(() => {
30257
- init_src();
30258
- ROUTES = {
30259
- INDEX: "/api",
30260
- HEALTH: "/api/health",
30261
- ASSETS: `${ASSET_ROUTE_PREFIX}*`,
30262
- TIMEBACK: {
30263
- END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
30264
- GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`,
30265
- GET_MASTERY: `/api${TIMEBACK_ROUTES.GET_MASTERY}`,
30266
- GET_HIGHEST_GRADE_MASTERED: `/api${TIMEBACK_ROUTES.GET_HIGHEST_GRADE_MASTERED}`,
30267
- HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}`,
30268
- ADVANCE_COURSE: `/api${TIMEBACK_ROUTES.ADVANCE_COURSE}`,
30269
- UNENROLL_COURSE: `/api${TIMEBACK_ROUTES.UNENROLL_COURSE}`
30270
- }
30271
- };
30272
- });
30273
- // ../edge-play/src/entry/setup.ts
30987
+ // ../edge-play/src/game/setup.ts
30274
30988
  function prefixSecrets(secrets) {
30275
30989
  const prefixed = {};
30276
30990
  for (const [key, value] of Object.entries(secrets)) {
@@ -30280,7 +30994,6 @@ function prefixSecrets(secrets) {
30280
30994
  }
30281
30995
  var init_setup2 = __esm(() => {
30282
30996
  init_src();
30283
- init_constants3();
30284
30997
  });
30285
30998
 
30286
30999
  // ../api-core/src/services/seed.service.ts
@@ -30315,7 +31028,7 @@ class SeedService {
30315
31028
  async seed(slug, code, user, secrets) {
30316
31029
  const cf = this.getCloudflare();
30317
31030
  const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
30318
- const deploymentId = getDeploymentId(slug, this.deps.config.sstStage);
31031
+ const deploymentId = getGameDeploymentId(slug, this.deps.config.sstStage);
30319
31032
  const uniqueSuffix = Date.now().toString(36);
30320
31033
  const seedDeploymentId = `seed-${deploymentId}-${uniqueSuffix}`;
30321
31034
  setAttributes({
@@ -30806,7 +31519,7 @@ var init_emoji = __esm(() => {
30806
31519
  });
30807
31520
 
30808
31521
  // ../data/src/domains/game/schemas.ts
30809
- var HttpUrlSchema, GameEmojiSchema, GameMetadataRecordSchema, InsertGameSchema, UpdateGameSchema, InsertGameDeploymentSchema, InsertGameDeployJobSchema, UpsertGameMetadataSchema, PatchGameMetadataSchema, AddGameMemberSchema, UpdateGameMemberRoleSchema, ALLOWED_UPLOAD_EXTENSIONS, InitiateUploadSchema, AddCustomHostnameSchema, SetSecretsRequestSchema, SeedRequestSchema, SchemaInfoSchema, DatabaseResetRequestSchema, VerifyTokenSchema, KVSeedRequestSchema, DeployRequestSchema;
31522
+ var HttpUrlSchema, GameEmojiSchema, GameMetadataRecordSchema, InsertGameSchema, UpdateGameSchema, InsertGameDeploymentSchema, InsertGameDeployJobSchema, UpsertGameMetadataSchema, PatchGameMetadataSchema, AddGameMemberSchema, UpdateGameMemberRoleSchema, AddGameDashboardUserSchema, VerifyGameDashboardLoginSchema, AcceptGameDashboardInviteSchema, AcceptGameDashboardResetSchema, ALLOWED_UPLOAD_EXTENSIONS, InitiateUploadSchema, AddCustomHostnameSchema, SetSecretsRequestSchema, SeedRequestSchema, SchemaInfoSchema, DatabaseResetRequestSchema, VerifyTokenSchema, KVSeedRequestSchema, DeployRequestSchema;
30810
31523
  var init_schemas2 = __esm(() => {
30811
31524
  init_drizzle_zod();
30812
31525
  init_esm();
@@ -30917,6 +31630,20 @@ var init_schemas2 = __esm(() => {
30917
31630
  UpdateGameMemberRoleSchema = exports_external.object({
30918
31631
  role: exports_external.enum(gameMemberRoleEnum.enumValues)
30919
31632
  }).strict();
31633
+ AddGameDashboardUserSchema = exports_external.object({
31634
+ email: exports_external.string().email().max(255),
31635
+ displayName: exports_external.string().min(1).max(255).optional(),
31636
+ role: exports_external.enum(gameDashboardUserRoleEnum.enumValues).optional().default(DASHBOARD_USER_ROLES.VIEWER)
31637
+ }).strict();
31638
+ VerifyGameDashboardLoginSchema = exports_external.object({
31639
+ email: exports_external.string().email().max(255),
31640
+ password: exports_external.string().min(1).max(1024)
31641
+ }).strict();
31642
+ AcceptGameDashboardInviteSchema = exports_external.object({
31643
+ token: exports_external.string().min(1).max(255),
31644
+ password: exports_external.string().min(8, "Password must be at least 8 characters").max(1024, "Password must be at most 1024 characters")
31645
+ }).strict();
31646
+ AcceptGameDashboardResetSchema = AcceptGameDashboardInviteSchema;
30920
31647
  ALLOWED_UPLOAD_EXTENSIONS = [".zip", ".js"];
30921
31648
  InitiateUploadSchema = exports_external.object({
30922
31649
  fileName: exports_external.string().min(1).refine((name2) => ALLOWED_UPLOAD_EXTENSIONS.some((ext) => name2.endsWith(ext)), {
@@ -30951,6 +31678,7 @@ var init_schemas2 = __esm(() => {
30951
31678
  }))
30952
31679
  });
30953
31680
  DeployRequestSchema = exports_external.object({
31681
+ target: exports_external.enum(deploymentTargetEnum.enumValues).optional().default("game"),
30954
31682
  uploadToken: exports_external.string().optional(),
30955
31683
  code: exports_external.string().optional(),
30956
31684
  codeUploadToken: exports_external.string().optional(),
@@ -30986,6 +31714,9 @@ var init_schemas2 = __esm(() => {
30986
31714
  }).refine((data) => !(data.code && data.codeUploadToken), {
30987
31715
  message: "Specify either code or codeUploadToken, not both",
30988
31716
  path: ["codeUploadToken"]
31717
+ }).refine((data) => !(data.target === "dashboard" && (data.schema || data.bindings)), {
31718
+ message: "Dashboard deployments cannot include schema or bindings — they attach to the game deployment’s existing resources",
31719
+ path: ["target"]
30989
31720
  });
30990
31721
  });
30991
31722
 
@@ -74417,6 +75148,17 @@ function isValidUUID(value) {
74417
75148
  }
74418
75149
  return UUID_REGEX.test(value);
74419
75150
  }
75151
+ async function deterministicUUID(input) {
75152
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
75153
+ const bytes = new Uint8Array(digest).slice(0, 16);
75154
+ bytes[6] = bytes[6] & 15 | 80;
75155
+ bytes[8] = bytes[8] & 63 | 128;
75156
+ const hex3 = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
75157
+ return `${hex3.slice(0, 8)}-${hex3.slice(8, 12)}-${hex3.slice(12, 16)}-${hex3.slice(16, 20)}-${hex3.slice(20)}`;
75158
+ }
75159
+ async function localGameId(slug) {
75160
+ return deterministicUUID(`playcademy:local-game:${slug}`);
75161
+ }
74420
75162
  var UUID_REGEX;
74421
75163
  var init_uuid2 = __esm(() => {
74422
75164
  UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
@@ -76818,7 +77560,7 @@ function deriveTimebackCourseLevelFromGrade(grade) {
76818
77560
  return TIMEBACK_COURSE_DEFAULTS.level.high;
76819
77561
  }
76820
77562
  var ONEROSTER_STATUS2, SCORE_STATUS2, CACHE_DEFAULTS3, RESOURCE_DEFAULTS3;
76821
- var init_constants4 = __esm(() => {
77563
+ var init_constants3 = __esm(() => {
76822
77564
  init_src();
76823
77565
  ONEROSTER_STATUS2 = {
76824
77566
  active: "active",
@@ -77792,7 +78534,7 @@ function qtiIdCandidates(parentLineItem, resource) {
77792
78534
  }
77793
78535
  var GRADE_LEVEL_TEST_TYPES, naturalTitleSort;
77794
78536
  var init_timeback_grade_level_results_util = __esm(() => {
77795
- init_constants4();
78537
+ init_constants3();
77796
78538
  GRADE_LEVEL_TEST_TYPES = [
77797
78539
  "placement",
77798
78540
  "test out",
@@ -77987,7 +78729,7 @@ async function upsertMasteryCompletionEntry(params) {
77987
78729
  }
77988
78730
  var init_timeback_mastery_completion_util = __esm(async () => {
77989
78731
  init_spans();
77990
- init_constants4();
78732
+ init_constants3();
77991
78733
  init_utils6();
77992
78734
  await init_errors8();
77993
78735
  });
@@ -78683,7 +79425,7 @@ class TimebackAdminService {
78683
79425
  columns: { slug: true }
78684
79426
  }),
78685
79427
  this.deps.db.query.gameDeployments.findFirst({
78686
- where: and(eq(gameDeployments.gameId, gameId), eq(gameDeployments.isActive, true)),
79428
+ where: activeDeploymentWhere(gameId),
78687
79429
  columns: { url: true }
78688
79430
  })
78689
79431
  ]);
@@ -79764,7 +80506,7 @@ var init_timeback_admin_service = __esm(async () => {
79764
80506
  init_schemas_index();
79765
80507
  init_tables_index();
79766
80508
  init_spans();
79767
- init_constants4();
80509
+ init_constants3();
79768
80510
  init_types2();
79769
80511
  init_utils6();
79770
80512
  init_src4();
@@ -80239,7 +80981,7 @@ function timebackConfigMatchesCreateIntegrationRequest(config4, request) {
80239
80981
  return subject === request.subject && grade === request.grade && config4.course.title === request.title && config4.course.courseCode === request.courseCode && config4.course.level === requestedLevel && (getTotalXpFromTimebackConfig(config4) ?? null) === request.totalXp && (getMasterableUnitsFromTimebackConfig(config4) ?? null) === request.masterableUnits;
80240
80982
  }
80241
80983
  var init_timeback_create_integration_util = __esm(() => {
80242
- init_constants4();
80984
+ init_constants3();
80243
80985
  init_types2();
80244
80986
  init_timeback_util();
80245
80987
  });
@@ -83085,6 +83827,19 @@ function createSandboxAuthProvider() {
83085
83827
  }
83086
83828
  return null;
83087
83829
  },
83830
+ async deleteApiKeysByName(name3) {
83831
+ const deleted = [];
83832
+ for (const [id, key] of sandboxApiKeys.entries()) {
83833
+ if (key.name === name3) {
83834
+ sandboxApiKeys.delete(id);
83835
+ deleted.push(id);
83836
+ }
83837
+ }
83838
+ if (deleted.length > 0) {
83839
+ log.debug("[SandboxAuthProvider] Deleted API keys by name", { name: name3, deleted });
83840
+ }
83841
+ return deleted;
83842
+ },
83088
83843
  async mintGameToken(gameId, userId) {
83089
83844
  const header = btoa(JSON.stringify({ alg: "none", typ: "sandbox" }));
83090
83845
  const exp = Date.now() + 15 * 60 * 1000;
@@ -83163,6 +83918,12 @@ function createSandboxAuthProvider() {
83163
83918
  } catch {
83164
83919
  return null;
83165
83920
  }
83921
+ },
83922
+ async hashPassword(password) {
83923
+ return `sandbox:${btoa(password)}`;
83924
+ },
83925
+ async verifyPassword(data) {
83926
+ return data.hash === `sandbox:${btoa(data.password)}`;
83166
83927
  }
83167
83928
  };
83168
83929
  }
@@ -83447,7 +84208,7 @@ var init_http_exception = () => {};
83447
84208
 
83448
84209
  // ../../node_modules/.bun/hono@4.10.7/node_modules/hono/dist/request/constants.js
83449
84210
  var GET_MATCH_RESULT;
83450
- var init_constants5 = __esm(() => {
84211
+ var init_constants4 = __esm(() => {
83451
84212
  GET_MATCH_RESULT = Symbol();
83452
84213
  });
83453
84214
 
@@ -83711,7 +84472,7 @@ var init_url = __esm(() => {
83711
84472
  var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_), HonoRequest;
83712
84473
  var init_request = __esm(() => {
83713
84474
  init_http_exception();
83714
- init_constants5();
84475
+ init_constants4();
83715
84476
  init_body();
83716
84477
  init_url();
83717
84478
  HonoRequest = class {
@@ -84041,7 +84802,7 @@ var init_router = __esm(() => {
84041
84802
 
84042
84803
  // ../../node_modules/.bun/hono@4.10.7/node_modules/hono/dist/utils/constants.js
84043
84804
  var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
84044
- var init_constants6 = () => {};
84805
+ var init_constants5 = () => {};
84045
84806
 
84046
84807
  // ../../node_modules/.bun/hono@4.10.7/node_modules/hono/dist/hono-base.js
84047
84808
  var notFoundHandler = (c) => {
@@ -84263,7 +85024,7 @@ var init_hono_base = __esm(() => {
84263
85024
  init_compose();
84264
85025
  init_context2();
84265
85026
  init_router();
84266
- init_constants6();
85027
+ init_constants5();
84267
85028
  init_url();
84268
85029
  });
84269
85030
 
@@ -92933,7 +93694,7 @@ var require_node3 = __commonJS((exports) => {
92933
93694
  exports2.isAbsolute = function(aPath) {
92934
93695
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
92935
93696
  };
92936
- function relative(aRoot, aPath) {
93697
+ function relative2(aRoot, aPath) {
92937
93698
  if (aRoot === "") {
92938
93699
  aRoot = ".";
92939
93700
  }
@@ -92952,7 +93713,7 @@ var require_node3 = __commonJS((exports) => {
92952
93713
  }
92953
93714
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
92954
93715
  }
92955
- exports2.relative = relative;
93716
+ exports2.relative = relative2;
92956
93717
  var supportsNullProto = function() {
92957
93718
  var obj = Object.create(null);
92958
93719
  return !("__proto__" in obj);
@@ -94983,7 +95744,7 @@ If you have no idea what this means or what Pirates is, let me explain: Pirates
94983
95744
  });
94984
95745
  };
94985
95746
  }
94986
- var readFile = (fp) => new Promise((resolve2, reject) => {
95747
+ var readFile2 = (fp) => new Promise((resolve2, reject) => {
94987
95748
  _fs.default.readFile(fp, "utf8", (err2, data) => {
94988
95749
  if (err2)
94989
95750
  return reject(err2);
@@ -95181,7 +95942,7 @@ If you have no idea what this means or what Pirates is, let me explain: Pirates
95181
95942
  data: _this3.packageJsonCache.get(filepath)[options.packageKey]
95182
95943
  };
95183
95944
  }
95184
- const data = _this3.options.parseJSON(yield readFile(filepath));
95945
+ const data = _this3.options.parseJSON(yield readFile2(filepath));
95185
95946
  return {
95186
95947
  path: filepath,
95187
95948
  data
@@ -95189,7 +95950,7 @@ If you have no idea what this means or what Pirates is, let me explain: Pirates
95189
95950
  }
95190
95951
  return {
95191
95952
  path: filepath,
95192
- data: yield readFile(filepath)
95953
+ data: yield readFile2(filepath)
95193
95954
  };
95194
95955
  }
95195
95956
  return {};
@@ -100234,7 +100995,7 @@ var __create2, __defProp2, __getOwnPropDesc, __getOwnPropNames2, __getProtoOf2,
100234
100995
  __defProp2(to, key, { get: () => from[key], enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable });
100235
100996
  }
100236
100997
  return to;
100237
- }, __toESM5 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target, mod)), __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value), ANSI_BACKGROUND_OFFSET, wrapAnsi16, wrapAnsi256, wrapAnsi16m, styles2, modifierNames, foregroundColorNames, backgroundColorNames, colorNames, ansiStyles, ansi_styles_default, init_ansi_styles, env, flagForceColor, supportsColor, supports_color_default, init_supports_color, init_utilities, stdoutColor, stderrColor, GENERATOR, STYLER, IS_EMPTY, levelMapping, styles22, applyOptions, chalkFactory, getModelAnsi, usedModels, proto, createStyler, createBuilder, applyStyle, chalk, chalkStderr, source_default, init_source, require_old, require_fs, require_path, require_balanced_match, require_brace_expansion, require_minimatch, require_inherits_browser2, require_inherits2, require_common3, require_sync, require_wrappy, require_once, require_inflight, require_glob, require_readline, require_src3, require_utils4, require_lodash, require_hanji, originUUID, snapshotVersion, mapValues, mapKeys, mapEntries, customMapEntries, init_global2, util3, objectUtil2, ZodParsedType2, getParsedType4, init_util4, ZodIssueCode4, ZodError5, init_ZodError2, errorMap2, en_default4, init_en4, overrideErrorMap2, init_errors9, makeIssue2, ParseStatus2, INVALID3, DIRTY2, OK2, isAborted2, isDirty2, isValid2, isAsync2, init_parseUtil2, init_typeAliases2, errorUtil2, init_errorUtil2, ParseInputLazyPath2, handleResult2, ZodType4, cuidRegex2, cuid2Regex2, ulidRegex2, uuidRegex2, nanoidRegex2, jwtRegex2, durationRegex2, emailRegex2, _emojiRegex2, emojiRegex2, ipv4Regex2, ipv4CidrRegex2, ipv6Regex2, ipv6CidrRegex2, base64Regex2, base64urlRegex2, dateRegexSource2, dateRegex2, ZodString4, ZodNumber4, ZodBigInt4, ZodBoolean4, ZodDate4, ZodSymbol4, ZodUndefined4, ZodNull4, ZodAny4, ZodUnknown4, ZodNever4, ZodVoid4, ZodArray4, ZodObject4, ZodUnion4, getDiscriminator2, ZodDiscriminatedUnion4, ZodIntersection4, ZodTuple4, ZodRecord4, ZodMap4, ZodSet4, ZodFunction3, ZodLazy4, ZodLiteral4, ZodEnum4, ZodNativeEnum2, ZodPromise4, ZodEffects2, ZodOptional4, ZodNullable4, ZodDefault4, ZodCatch4, ZodNaN4, BRAND2, ZodBranded2, ZodPipeline2, ZodReadonly4, late2, ZodFirstPartyTypeKind3, stringType2, numberType2, nanType2, bigIntType2, booleanType2, dateType2, symbolType2, undefinedType2, nullType2, anyType2, unknownType2, neverType2, voidType2, arrayType2, objectType2, strictObjectType2, unionType2, discriminatedUnionType2, intersectionType2, tupleType2, recordType2, mapType2, setType2, functionType2, lazyType2, literalType2, enumType2, nativeEnumType2, promiseType2, effectsType2, optionalType2, nullableType2, preprocessType2, pipelineType2, coerce2, init_types5, init_external4, init_v32, init_esm2, enumSchema, enumSchemaV1, indexColumn, index2, fk, sequenceSchema, roleSchema, sequenceSquashed, column2, checkConstraint, columnSquashed, compositePK, uniqueConstraint, policy, policySquashed, viewWithOption, matViewWithOption, mergedViewWithOption, view2, table8, schemaHash, kitInternals, gelSchemaExternal, gelSchemaInternal, tableSquashed, gelSchemaSquashed, gelSchema, dryGel, init_gelSchema, index22, fk2, column22, tableV3, compositePK2, uniqueConstraint2, checkConstraint2, tableV4, table22, viewMeta, view22, kitInternals2, dialect2, schemaHash2, schemaInternalV3, schemaInternalV4, schemaInternalV5, schemaInternal, schemaV3, schemaV4, schemaV5, schema2, tableSquashedV4, tableSquashed2, viewSquashed, schemaSquashed, schemaSquashedV4, MySqlSquasher, squashMysqlScheme, mysqlSchema, mysqlSchemaV5, mysqlSchemaSquashed, backwardCompatibleMysqlSchema, dryMySql, init_mysqlSchema, indexV2, columnV2, tableV2, enumSchemaV12, enumSchema2, pgSchemaV2, references, columnV1, tableV1, pgSchemaV1, indexColumn2, index3, indexV4, indexV5, indexV6, fk3, sequenceSchema2, roleSchema2, sequenceSquashed2, columnV7, column3, checkConstraint3, columnSquashed2, tableV32, compositePK3, uniqueConstraint3, policy2, policySquashed2, viewWithOption2, matViewWithOption2, mergedViewWithOption2, view3, tableV42, tableV5, tableV6, tableV7, table32, schemaHash3, kitInternals3, pgSchemaInternalV3, pgSchemaInternalV4, pgSchemaInternalV5, pgSchemaInternalV6, pgSchemaExternal, pgSchemaInternalV7, pgSchemaInternal, tableSquashed3, tableSquashedV42, pgSchemaSquashedV4, pgSchemaSquashedV6, pgSchemaSquashed, pgSchemaV3, pgSchemaV4, pgSchemaV5, pgSchemaV6, pgSchemaV7, pgSchema, backwardCompatiblePgSchema, PgSquasher, squashPgScheme, dryPg, init_pgSchema, index4, column4, compositePK4, uniqueConstraint4, table42, viewMeta2, kitInternals4, dialect22, schemaHash4, schemaInternal2, schema22, tableSquashed4, schemaSquashed2, SingleStoreSquasher, squashSingleStoreScheme, singlestoreSchema, singlestoreSchemaSquashed, backwardCompatibleSingleStoreSchema, drySingleStore, init_singlestoreSchema, index5, fk4, compositePK5, column5, tableV33, uniqueConstraint5, checkConstraint4, table52, view4, dialect3, schemaHash5, schemaInternalV32, schemaInternalV42, schemaInternalV52, kitInternals5, latestVersion, schemaInternal3, schemaV32, schemaV42, schemaV52, schema3, tableSquashed5, schemaSquashed3, SQLiteSquasher, squashSqliteScheme, drySQLite, sqliteSchemaV5, sqliteSchema, SQLiteSchemaSquashed, backwardCompatibleSqliteSchema, init_sqliteSchema, copy, prepareMigrationMeta, schemaRenameKey, tableRenameKey, columnRenameKey, init_utils7, import_hanji, warning, error88, isRenamePromptItem, ResolveColumnSelect, tableKey, ResolveSelectNamed, ResolveSelect, ResolveSchemasSelect, Spinner2, ProgressView, init_views, glob, init_serializer, fillPgSnapshot, init_migrationPreparator, require_heap, require_heap2, require_difflib, require_difflib2, require_util2, require_styles, require_has_flag2, require_supports_colors, require_trap, require_zalgo, require_america, require_zebra, require_rainbow, require_random, require_colors, require_safe, require_colorize, require_lib4, import_json_diff, mapArraysDiff, findAlternationsInTable, alternationsInColumn, init_jsonDiffer, parseType, Convertor, PgCreateRoleConvertor, PgDropRoleConvertor, PgRenameRoleConvertor, PgAlterRoleConvertor, PgCreatePolicyConvertor, PgDropPolicyConvertor, PgRenamePolicyConvertor, PgAlterPolicyConvertor, PgCreateIndPolicyConvertor, PgDropIndPolicyConvertor, PgRenameIndPolicyConvertor, PgAlterIndPolicyConvertor, PgEnableRlsConvertor, PgDisableRlsConvertor, PgCreateTableConvertor, MySqlCreateTableConvertor, SingleStoreCreateTableConvertor, SQLiteCreateTableConvertor, PgCreateViewConvertor, MySqlCreateViewConvertor, SqliteCreateViewConvertor, PgDropViewConvertor, MySqlDropViewConvertor, SqliteDropViewConvertor, MySqlAlterViewConvertor, PgRenameViewConvertor, MySqlRenameViewConvertor, PgAlterViewSchemaConvertor, PgAlterViewAddWithOptionConvertor, PgAlterViewDropWithOptionConvertor, PgAlterViewAlterTablespaceConvertor, PgAlterViewAlterUsingConvertor, PgAlterTableAlterColumnSetGenerated, PgAlterTableAlterColumnDropGenerated, PgAlterTableAlterColumnAlterGenerated, PgAlterTableAddUniqueConstraintConvertor, PgAlterTableDropUniqueConstraintConvertor, PgAlterTableAddCheckConstraintConvertor, PgAlterTableDeleteCheckConstraintConvertor, MySQLAlterTableAddUniqueConstraintConvertor, MySQLAlterTableDropUniqueConstraintConvertor, MySqlAlterTableAddCheckConstraintConvertor, SingleStoreAlterTableAddUniqueConstraintConvertor, SingleStoreAlterTableDropUniqueConstraintConvertor, MySqlAlterTableDeleteCheckConstraintConvertor, CreatePgSequenceConvertor, DropPgSequenceConvertor, RenamePgSequenceConvertor, MovePgSequenceConvertor, AlterPgSequenceConvertor, CreateTypeEnumConvertor, DropTypeEnumConvertor, AlterTypeAddValueConvertor, AlterTypeSetSchemaConvertor, AlterRenameTypeConvertor, AlterTypeDropValueConvertor, PgDropTableConvertor, MySQLDropTableConvertor, SingleStoreDropTableConvertor, SQLiteDropTableConvertor, PgRenameTableConvertor, SqliteRenameTableConvertor, MySqlRenameTableConvertor, SingleStoreRenameTableConvertor, PgAlterTableRenameColumnConvertor, MySqlAlterTableRenameColumnConvertor, SingleStoreAlterTableRenameColumnConvertor, SQLiteAlterTableRenameColumnConvertor, PgAlterTableDropColumnConvertor, MySqlAlterTableDropColumnConvertor, SingleStoreAlterTableDropColumnConvertor, SQLiteAlterTableDropColumnConvertor, PgAlterTableAddColumnConvertor, MySqlAlterTableAddColumnConvertor, SingleStoreAlterTableAddColumnConvertor, SQLiteAlterTableAddColumnConvertor, PgAlterTableAlterColumnSetTypeConvertor, PgAlterTableAlterColumnSetDefaultConvertor, PgAlterTableAlterColumnDropDefaultConvertor, PgAlterTableAlterColumnDropGeneratedConvertor, PgAlterTableAlterColumnSetExpressionConvertor, PgAlterTableAlterColumnAlterrGeneratedConvertor, SqliteAlterTableAlterColumnDropGeneratedConvertor, SqliteAlterTableAlterColumnSetExpressionConvertor, SqliteAlterTableAlterColumnAlterGeneratedConvertor, MySqlAlterTableAlterColumnAlterrGeneratedConvertor, MySqlAlterTableAddPk, MySqlAlterTableDropPk, LibSQLModifyColumn, MySqlModifyColumn, SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor, SingleStoreAlterTableAddPk, SingleStoreAlterTableDropPk, SingleStoreModifyColumn, PgAlterTableCreateCompositePrimaryKeyConvertor, PgAlterTableDeleteCompositePrimaryKeyConvertor, PgAlterTableAlterCompositePrimaryKeyConvertor, MySqlAlterTableCreateCompositePrimaryKeyConvertor, MySqlAlterTableDeleteCompositePrimaryKeyConvertor, MySqlAlterTableAlterCompositePrimaryKeyConvertor, PgAlterTableAlterColumnSetPrimaryKeyConvertor, PgAlterTableAlterColumnDropPrimaryKeyConvertor, PgAlterTableAlterColumnSetNotNullConvertor, PgAlterTableAlterColumnDropNotNullConvertor, PgCreateForeignKeyConvertor, LibSQLCreateForeignKeyConvertor, MySqlCreateForeignKeyConvertor, PgAlterForeignKeyConvertor, PgDeleteForeignKeyConvertor, MySqlDeleteForeignKeyConvertor, CreatePgIndexConvertor, CreateMySqlIndexConvertor, CreateSingleStoreIndexConvertor, CreateSqliteIndexConvertor, PgDropIndexConvertor, PgCreateSchemaConvertor, PgRenameSchemaConvertor, PgDropSchemaConvertor, PgAlterTableSetSchemaConvertor, PgAlterTableSetNewSchemaConvertor, PgAlterTableRemoveFromSchemaConvertor, SqliteDropIndexConvertor, MySqlDropIndexConvertor, SingleStoreDropIndexConvertor, SQLiteRecreateTableConvertor, LibSQLRecreateTableConvertor, SingleStoreRecreateTableConvertor, convertors, init_sqlgenerator, _moveDataStatements, getOldTableName, getNewTableName, logSuggestionsAndReturn, init_sqlitePushUtils, preparePgCreateTableJson, prepareMySqlCreateTableJson, prepareSingleStoreCreateTableJson, prepareSQLiteCreateTable, prepareDropTableJson, prepareRenameTableJson, prepareCreateEnumJson, prepareAddValuesToEnumJson, prepareDropEnumValues, prepareDropEnumJson, prepareMoveEnumJson, prepareRenameEnumJson, prepareCreateSequenceJson, prepareAlterSequenceJson, prepareDropSequenceJson, prepareMoveSequenceJson, prepareRenameSequenceJson, prepareCreateRoleJson, prepareAlterRoleJson, prepareDropRoleJson, prepareRenameRoleJson, prepareCreateSchemasJson, prepareRenameSchemasJson, prepareDeleteSchemasJson, prepareRenameColumns, _prepareDropColumns, _prepareAddColumns, _prepareSqliteAddColumns, prepareAlterColumnsMysql, preparePgAlterColumns, prepareSqliteAlterColumns, prepareRenamePolicyJsons, prepareRenameIndPolicyJsons, prepareCreatePolicyJsons, prepareCreateIndPolicyJsons, prepareDropPolicyJsons, prepareDropIndPolicyJsons, prepareAlterPolicyJson, prepareAlterIndPolicyJson, preparePgCreateIndexesJson, prepareCreateIndexesJson, prepareCreateReferencesJson, prepareLibSQLCreateReferencesJson, prepareDropReferencesJson, prepareLibSQLDropReferencesJson, prepareAlterReferencesJson, prepareDropIndexesJson, prepareAddCompositePrimaryKeySqlite, prepareDeleteCompositePrimaryKeySqlite, prepareAlterCompositePrimaryKeySqlite, prepareAddCompositePrimaryKeyPg, prepareDeleteCompositePrimaryKeyPg, prepareAlterCompositePrimaryKeyPg, prepareAddUniqueConstraintPg, prepareDeleteUniqueConstraintPg, prepareAddCheckConstraint, prepareDeleteCheckConstraint, prepareAddCompositePrimaryKeyMySql, prepareDeleteCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyMySql, preparePgCreateViewJson, prepareMySqlCreateViewJson, prepareSqliteCreateViewJson, prepareDropViewJson, prepareRenameViewJson, preparePgAlterViewAlterSchemaJson, preparePgAlterViewAddWithOptionJson, preparePgAlterViewDropWithOptionJson, preparePgAlterViewAlterTablespaceJson, preparePgAlterViewAlterUsingJson, prepareMySqlAlterView, init_jsonStatements, prepareLibSQLRecreateTable, prepareSQLiteRecreateTable, libSQLCombineStatements, sqliteCombineStatements, prepareSingleStoreRecreateTable, singleStoreCombineStatements, init_statementCombiner, snapshotsDiffer_exports, makeChanged, makeSelfOrChanged, makePatched, makeSelfOrPatched, columnSchema, alteredColumnSchema, enumSchema3, changedEnumSchema, tableScheme, alteredTableScheme, alteredViewCommon, alteredPgViewSchema, alteredMySqlViewSchema, diffResultScheme, diffResultSchemeMysql, diffResultSchemeSingleStore, diffResultSchemeSQLite, schemaChangeFor, nameChangeFor, nameSchemaChangeFor, columnChangeFor, applyPgSnapshotsDiff, applyMysqlSnapshotsDiff, applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, applyLibSQLSnapshotsDiff, init_snapshotsDiffer, init_words, dialects, dialect4, commonSquashedSchema, commonSchema, init_schemaValidator, sqliteDriversLiterals, postgresqlDriversLiterals, prefixes, prefix, casingTypes, casingType, sqliteDriver, postgresDriver, driver2, configMigrations, configCommonSchema, casing, introspectParams, configIntrospectCliSchema, configGenerateSchema, configPushSchema, init_common2, withStyle, init_outputs, import_hanji2, schemasResolver, tablesResolver, viewsResolver, mySqlViewsResolver, sqliteViewsResolver, sequencesResolver, roleResolver, policyResolver, indPolicyResolver, enumsResolver, columnsResolver, promptColumnsConflicts, promptNamedConflict, promptNamedWithSchemasConflict, promptSchemasConflict, BREAKPOINT, init_migrate, posixClasses, braceEscape, regexpEscape, rangesToString, parseClass, init_brace_expressions, escape, init_escape, unescape, init_unescape, import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path, sep, GLOBSTAR, plTypes, qmark, star, twoStarDot, twoStarNoDot, charSet, reSpecials, addPatternStartSet, filter, ext, defaults, braceExpand, MAX_PATTERN_LENGTH, assertValidPattern, makeRe, match2, globUnescape, globMagic, regExpEscape, Minimatch, init_mjs, entityKind2, hasOwnEntityKind2, init_entity2, _a3, Column2, init_column2, _a22, ColumnBuilder2, init_column_builder2, TableName2, init_table_utils2, _a32, ForeignKeyBuilder2, _a4, ForeignKey2, init_foreign_keys2, init_tracing_utils2, _a5, UniqueConstraintBuilder, _a6, UniqueOnConstraintBuilder, _a7, UniqueConstraint, init_unique_constraint2, init_array2, _a8, _b, PgColumnBuilder2, _a9, _b2, PgColumn2, _a10, _b3, ExtraConfigColumn2, _a11, IndexedColumn2, _a12, _b4, PgArrayBuilder2, _a13, _b5, _PgArray, PgArray2, init_common22, _a14, _b6, PgEnumObjectColumnBuilder2, _a15, _b7, PgEnumObjectColumn2, isPgEnumSym2, _a16, _b8, PgEnumColumnBuilder2, _a17, _b9, PgEnumColumn2, init_enum2, _a18, Subquery2, _a19, _b10, WithSubquery2, init_subquery2, version4, init_version2, otel2, rawTracer2, tracer2, init_tracing2, ViewBaseConfig2, init_view_common3, Schema2, Columns2, ExtraConfigColumns2, OriginalName2, BaseName2, IsAlias2, ExtraConfigBuilder2, IsDrizzleTable2, _a20, _b11, _c, _d, _e3, _f, _g, _h, _i, _j, Table2, init_table8, _a21, FakePrimitiveParam, _a222, StringChunk2, _a23, _SQL, SQL2, _a24, Name2, noopDecoder2, noopEncoder2, noopMapper2, _a25, Param2, _a26, Placeholder2, IsDrizzleView2, _a27, _b12, _c2, View3, init_sql3, _a28, ColumnAliasProxyHandler2, _a29, TableAliasProxyHandler2, _a30, RelationTableAliasProxyHandler, init_alias3, _a31, _b13, DrizzleError2, DrizzleQueryError, _a322, _b14, TransactionRollbackError2, init_errors22, _a33, ConsoleLogWriter2, _a34, DefaultLogger2, _a35, NoopLogger2, init_logger3, init_operations, _a36, _b15, QueryPromise2, init_query_promise2, textDecoder, init_utils22, _a37, _b16, PgIntColumnBaseBuilder2, init_int_common2, _a38, _b17, PgBigInt53Builder2, _a39, _b18, PgBigInt532, _a40, _b19, PgBigInt64Builder2, _a41, _b20, PgBigInt642, init_bigint2, _a42, _b21, PgBigSerial53Builder2, _a43, _b22, PgBigSerial532, _a44, _b23, PgBigSerial64Builder2, _a45, _b24, PgBigSerial642, init_bigserial2, _a46, _b25, PgBooleanBuilder2, _a47, _b26, PgBoolean2, init_boolean2, _a48, _b27, PgCharBuilder2, _a49, _b28, PgChar2, init_char2, _a50, _b29, PgCidrBuilder2, _a51, _b30, PgCidr2, init_cidr2, _a52, _b31, PgCustomColumnBuilder2, _a53, _b32, PgCustomColumn2, init_custom2, _a54, _b33, PgDateColumnBaseBuilder2, init_date_common2, _a55, _b34, PgDateBuilder2, _a56, _b35, PgDate2, _a57, _b36, PgDateStringBuilder2, _a58, _b37, PgDateString2, init_date2, _a59, _b38, PgDoublePrecisionBuilder2, _a60, _b39, PgDoublePrecision2, init_double_precision2, _a61, _b40, PgInetBuilder2, _a62, _b41, PgInet2, init_inet2, _a63, _b42, PgIntegerBuilder2, _a64, _b43, PgInteger2, init_integer2, _a65, _b44, PgIntervalBuilder2, _a66, _b45, PgInterval2, init_interval2, _a67, _b46, PgJsonBuilder2, _a68, _b47, PgJson2, init_json2, _a69, _b48, PgJsonbBuilder2, _a70, _b49, PgJsonb2, init_jsonb2, _a71, _b50, PgLineBuilder2, _a72, _b51, PgLineTuple2, _a73, _b52, PgLineABCBuilder2, _a74, _b53, PgLineABC2, init_line2, _a75, _b54, PgMacaddrBuilder2, _a76, _b55, PgMacaddr2, init_macaddr2, _a77, _b56, PgMacaddr8Builder2, _a78, _b57, PgMacaddr82, init_macaddr82, _a79, _b58, PgNumericBuilder2, _a80, _b59, PgNumeric2, _a81, _b60, PgNumericNumberBuilder2, _a82, _b61, PgNumericNumber2, _a83, _b62, PgNumericBigIntBuilder2, _a84, _b63, PgNumericBigInt2, init_numeric2, _a85, _b64, PgPointTupleBuilder2, _a86, _b65, PgPointTuple2, _a87, _b66, PgPointObjectBuilder2, _a88, _b67, PgPointObject2, init_point2, init_utils32, _a89, _b68, PgGeometryBuilder2, _a90, _b69, PgGeometry2, _a91, _b70, PgGeometryObjectBuilder2, _a92, _b71, PgGeometryObject2, init_geometry2, _a93, _b72, PgRealBuilder2, _a94, _b73, PgReal2, init_real2, _a95, _b74, PgSerialBuilder2, _a96, _b75, PgSerial2, init_serial2, _a97, _b76, PgSmallIntBuilder2, _a98, _b77, PgSmallInt2, init_smallint2, _a99, _b78, PgSmallSerialBuilder2, _a100, _b79, PgSmallSerial2, init_smallserial2, _a101, _b80, PgTextBuilder2, _a102, _b81, PgText2, init_text2, _a103, _b82, PgTimeBuilder2, _a104, _b83, PgTime2, init_time2, _a105, _b84, PgTimestampBuilder2, _a106, _b85, PgTimestamp2, _a107, _b86, PgTimestampStringBuilder2, _a108, _b87, PgTimestampString2, init_timestamp2, _a109, _b88, PgUUIDBuilder2, _a110, _b89, PgUUID2, init_uuid3, _a111, _b90, PgVarcharBuilder2, _a112, _b91, PgVarchar2, init_varchar2, _a113, _b92, PgBinaryVectorBuilder2, _a114, _b93, PgBinaryVector2, init_bit2, _a115, _b94, PgHalfVectorBuilder2, _a116, _b95, PgHalfVector2, init_halfvec2, _a117, _b96, PgSparseVectorBuilder2, _a118, _b97, PgSparseVector2, init_sparsevec2, _a119, _b98, PgVectorBuilder2, _a120, _b99, PgVector2, init_vector3, init_all2, InlineForeignKeys2, EnableRLS2, _a121, _b100, _c3, _d2, _e22, _f2, PgTable2, pgTable2, init_table22, _a122, PrimaryKeyBuilder2, _a123, PrimaryKey2, init_primary_keys2, eq2, ne4, gt3, gte2, lt4, lte2, init_conditions2, init_select3, init_expressions2, _a124, Relation2, _a125, Relations2, _a126, _b101, _One, One2, _a127, _b102, _Many, Many2, init_relations2, init_aggregate2, init_vector22, init_functions2, init_sql22, dist_exports, init_dist9, init_alias22, _a128, CheckBuilder, _a129, Check, init_checks6, init_columns2, _a130, _SelectionProxyHandler, SelectionProxyHandler2, init_selection_proxy2, _a131, IndexBuilderOn2, _a132, IndexBuilder2, _a133, Index2, init_indexes2, _a134, PgPolicy, init_policies2, PgViewConfig2, init_view_common22, _a135, CasingCache2, init_casing2, _a136, _b103, PgViewBase2, init_view_base2, _a137, PgDialect2, init_dialect2, _a138, TypedQueryBuilder2, init_query_builder3, _a139, PgSelectBuilder2, _a140, _b104, PgSelectQueryBuilderBase2, _a141, _b105, PgSelectBase2, getPgSetOperators2, union22, unionAll2, intersect2, intersectAll2, except2, exceptAll2, init_select22, _a142, QueryBuilder2, init_query_builder22, _a143, DefaultViewBuilderCore, _a144, _b106, ViewBuilder, _a145, _b107, ManualViewBuilder, _a146, MaterializedViewBuilderCore, _a147, _b108, MaterializedViewBuilder, _a148, _b109, ManualMaterializedViewBuilder, _a149, _b110, _c4, PgView2, PgMaterializedViewConfig2, _a150, _b111, _c5, PgMaterializedView, init_view2, init_utils42, _a151, _b112, PgDeleteBase2, init_delete2, _a152, PgInsertBuilder2, _a153, _b113, PgInsertBase2, init_insert2, _a154, _b114, PgRefreshMaterializedView2, init_refresh_materialized_view2, init_select_types, _a155, PgUpdateBuilder2, _a156, _b115, PgUpdateBase2, init_update2, init_query_builders2, _a157, _b116, _c6, _PgCountBuilder, PgCountBuilder2, init_count2, _a158, RelationalQueryBuilder2, _a159, _b117, PgRelationalQuery2, init_query2, _a160, _b118, PgRaw2, init_raw2, _a161, PgDatabase2, init_db2, _a162, PgRole, init_roles2, _a163, PgSequence, init_sequence2, _a164, PgSchema5, init_schema3, _a165, Cache, _a166, _b119, NoopCache, init_cache, _a167, PgPreparedQuery2, _a168, PgSession2, _a169, _b120, PgTransaction2, init_session3, init_subquery22, init_utils52, init_pg_core2, vectorOps, init_vector32, sqlToStr, init_utils62, indexName, generatePgSnapshot, trimChar, fromDatabase, defaultForColumn, getColumnsInfoQuery, init_pgSerializer, import_hanji4, Select, init_selector_ui, init_alias32, _a170, CheckBuilder2, _a171, Check2, init_checks22, _a172, ForeignKeyBuilder22, _a173, ForeignKey22, init_foreign_keys22, _a174, UniqueConstraintBuilder2, _a175, UniqueOnConstraintBuilder2, _a176, UniqueConstraint2, init_unique_constraint22, _a177, _b121, SQLiteColumnBuilder, _a178, _b122, SQLiteColumn, init_common3, _a179, _b123, SQLiteBigIntBuilder, _a180, _b124, SQLiteBigInt, _a181, _b125, SQLiteBlobJsonBuilder, _a182, _b126, SQLiteBlobJson, _a183, _b127, SQLiteBlobBufferBuilder, _a184, _b128, SQLiteBlobBuffer, init_blob, _a185, _b129, SQLiteCustomColumnBuilder, _a186, _b130, SQLiteCustomColumn, init_custom22, _a187, _b131, SQLiteBaseIntegerBuilder, _a188, _b132, SQLiteBaseInteger, _a189, _b133, SQLiteIntegerBuilder, _a190, _b134, SQLiteInteger, _a191, _b135, SQLiteTimestampBuilder, _a192, _b136, SQLiteTimestamp, _a193, _b137, SQLiteBooleanBuilder, _a194, _b138, SQLiteBoolean, init_integer22, _a195, _b139, SQLiteNumericBuilder, _a196, _b140, SQLiteNumeric, _a197, _b141, SQLiteNumericNumberBuilder, _a198, _b142, SQLiteNumericNumber, _a199, _b143, SQLiteNumericBigIntBuilder, _a200, _b144, SQLiteNumericBigInt, init_numeric22, _a201, _b145, SQLiteRealBuilder, _a202, _b146, SQLiteReal, init_real22, _a203, _b147, SQLiteTextBuilder, _a204, _b148, SQLiteText, _a205, _b149, SQLiteTextJsonBuilder, _a206, _b150, SQLiteTextJson, init_text22, init_columns22, init_all22, InlineForeignKeys22, _a207, _b151, _c7, _d3, _e32, SQLiteTable, sqliteTable, init_table32, _a208, IndexBuilderOn22, _a209, IndexBuilder22, _a210, Index4, init_indexes22, _a211, PrimaryKeyBuilder22, _a212, PrimaryKey22, init_primary_keys22, init_utils72, _a213, _b152, SQLiteDeleteBase, init_delete22, _a214, _b153, SQLiteViewBase, init_view_base22, _a215, SQLiteDialect, _a216, _b154, SQLiteSyncDialect, _a217, _b155, SQLiteAsyncDialect, init_dialect22, _a218, SQLiteSelectBuilder, _a219, _b156, SQLiteSelectQueryBuilderBase, _a220, _b157, SQLiteSelectBase, getSQLiteSetOperators, union32, unionAll22, intersect22, except22, init_select32, _a221, QueryBuilder22, init_query_builder32, _a2222, SQLiteInsertBuilder, _a223, _b158, SQLiteInsertBase, init_insert22, init_select_types2, _a224, SQLiteUpdateBuilder, _a225, _b159, SQLiteUpdateBase, init_update22, init_query_builders22, _a226, _b160, _c8, _SQLiteCountBuilder, SQLiteCountBuilder, init_count22, _a227, RelationalQueryBuilder22, _a228, _b161, SQLiteRelationalQuery, _a229, _b162, SQLiteSyncRelationalQuery, init_query22, _a230, _b163, SQLiteRaw, init_raw22, _a231, BaseSQLiteDatabase, init_db22, _a232, _b164, ExecuteResultSync, _a233, SQLitePreparedQuery, _a234, SQLiteSession, _a235, _b165, SQLiteTransaction, init_session22, init_subquery3, _a236, ViewBuilderCore, _a237, _b166, ViewBuilder2, _a238, _b167, ManualViewBuilder2, _a239, _b168, SQLiteView2, init_view22, init_sqlite_core, generateSqliteSnapshot, fromDatabase2, init_sqliteSerializer, getTablesFilterByExtensions, init_getTablesFilterByExtensions, init_alias4, _a240, CheckBuilder3, _a241, Check3, init_checks32, _a242, ForeignKeyBuilder3, _a243, ForeignKey3, init_foreign_keys3, _a244, UniqueConstraintBuilder3, _a245, UniqueOnConstraintBuilder3, _a246, UniqueConstraint3, init_unique_constraint3, _a247, _b169, MySqlColumnBuilder, _a248, _b170, MySqlColumn, _a249, _b171, MySqlColumnBuilderWithAutoIncrement, _a250, _b172, MySqlColumnWithAutoIncrement, init_common4, _a251, _b173, MySqlBigInt53Builder, _a252, _b174, MySqlBigInt53, _a253, _b175, MySqlBigInt64Builder, _a254, _b176, MySqlBigInt64, init_bigint22, _a255, _b177, MySqlBinaryBuilder, _a256, _b178, MySqlBinary, init_binary, _a257, _b179, MySqlBooleanBuilder, _a258, _b180, MySqlBoolean, init_boolean22, _a259, _b181, MySqlCharBuilder, _a260, _b182, MySqlChar, init_char22, _a261, _b183, MySqlCustomColumnBuilder, _a262, _b184, MySqlCustomColumn, init_custom3, _a263, _b185, MySqlDateBuilder, _a264, _b186, MySqlDate, _a265, _b187, MySqlDateStringBuilder, _a266, _b188, MySqlDateString, init_date22, _a267, _b189, MySqlDateTimeBuilder, _a268, _b190, MySqlDateTime, _a269, _b191, MySqlDateTimeStringBuilder, _a270, _b192, MySqlDateTimeString, init_datetime, _a271, _b193, MySqlDecimalBuilder, _a272, _b194, MySqlDecimal, _a273, _b195, MySqlDecimalNumberBuilder, _a274, _b196, MySqlDecimalNumber, _a275, _b197, MySqlDecimalBigIntBuilder, _a276, _b198, MySqlDecimalBigInt, init_decimal, _a277, _b199, MySqlDoubleBuilder, _a278, _b200, MySqlDouble, init_double, _a279, _b201, MySqlEnumColumnBuilder, _a280, _b202, MySqlEnumColumn, _a281, _b203, MySqlEnumObjectColumnBuilder, _a282, _b204, MySqlEnumObjectColumn, init_enum22, _a283, _b205, MySqlFloatBuilder, _a284, _b206, MySqlFloat, init_float, _a285, _b207, MySqlIntBuilder, _a286, _b208, MySqlInt, init_int, _a287, _b209, MySqlJsonBuilder, _a288, _b210, MySqlJson, init_json22, _a289, _b211, MySqlMediumIntBuilder, _a290, _b212, MySqlMediumInt, init_mediumint, _a291, _b213, MySqlRealBuilder, _a292, _b214, MySqlReal, init_real3, _a293, _b215, MySqlSerialBuilder, _a294, _b216, MySqlSerial, init_serial22, _a295, _b217, MySqlSmallIntBuilder, _a296, _b218, MySqlSmallInt, init_smallint22, _a297, _b219, MySqlTextBuilder, _a298, _b220, MySqlText, init_text3, _a299, _b221, MySqlTimeBuilder, _a300, _b222, MySqlTime, init_time22, _a301, _b223, MySqlDateColumnBaseBuilder, _a302, _b224, MySqlDateBaseColumn, init_date_common22, _a303, _b225, MySqlTimestampBuilder, _a304, _b226, MySqlTimestamp, _a305, _b227, MySqlTimestampStringBuilder, _a306, _b228, MySqlTimestampString, init_timestamp22, _a307, _b229, MySqlTinyIntBuilder, _a308, _b230, MySqlTinyInt, init_tinyint, _a309, _b231, MySqlVarBinaryBuilder, _a310, _b232, MySqlVarBinary, init_varbinary, _a311, _b233, MySqlVarCharBuilder, _a312, _b234, MySqlVarChar, init_varchar22, _a313, _b235, MySqlYearBuilder, _a314, _b236, MySqlYear, init_year, init_columns3, _a315, _b237, _c9, _MySqlCountBuilder, MySqlCountBuilder, init_count3, _a316, IndexBuilderOn3, _a317, IndexBuilder3, _a318, Index5, init_indexes3, init_all3, InlineForeignKeys3, _a319, _b238, _c10, _d4, _e4, MySqlTable, mysqlTable, init_table42, _a320, PrimaryKeyBuilder3, _a321, PrimaryKey3, init_primary_keys3, MySqlViewConfig, init_view_common32, init_utils8, _a3222, _b239, MySqlDeleteBase, init_delete3, _a323, _b240, MySqlViewBase, init_view_base3, _a324, MySqlDialect, init_dialect3, _a325, MySqlSelectBuilder, _a326, _b241, MySqlSelectQueryBuilderBase, _a327, _b242, MySqlSelectBase, getMySqlSetOperators, union4, unionAll3, intersect3, intersectAll22, except3, exceptAll22, init_select4, _a328, QueryBuilder3, init_query_builder4, _a329, MySqlInsertBuilder, _a330, _b243, MySqlInsertBase, init_insert3, init_select_types3, _a331, MySqlUpdateBuilder, _a332, _b244, MySqlUpdateBase, init_update3, init_query_builders3, _a333, RelationalQueryBuilder3, _a334, _b245, MySqlRelationalQuery, init_query3, _a335, MySqlDatabase, init_db3, _a336, ViewBuilderCore2, _a337, _b246, ViewBuilder3, _a338, _b247, ManualViewBuilder3, _a339, _b248, _c11, MySqlView2, init_view3, _a340, MySqlSchema5, init_schema22, _a341, MySqlPreparedQuery, _a342, MySqlSession, _a343, _b249, MySqlTransaction, init_session32, init_subquery4, init_mysql_core, handleEnumType, generateMySqlSnapshot, fromDatabase3, init_mysqlSerializer, cliConfigGenerate, pushParams, pullParams, configCheck, cliConfigCheck, init_cli, gelCredentials, init_gel, libSQLCredentials, init_libsql, mysqlCredentials, init_mysql, postgresCredentials, init_postgres, singlestoreCredentials, init_singlestore, sqliteCredentials, init_sqlite, credentials, studioCliParams, studioConfig, init_studio, es5_exports, _3, es5_default, init_es5, import_hanji7, assertES5, safeRegister, migrateConfig, init_utils9, prepareFromExports, init_pgImports, init_alias5, _a344, UniqueConstraintBuilder4, _a345, UniqueOnConstraintBuilder4, _a346, UniqueConstraint4, init_unique_constraint4, _a347, _b250, SingleStoreColumnBuilder, _a348, _b251, SingleStoreColumn, _a349, _b252, SingleStoreColumnBuilderWithAutoIncrement, _a350, _b253, SingleStoreColumnWithAutoIncrement, init_common5, _a351, _b254, SingleStoreBigInt53Builder, _a352, _b255, SingleStoreBigInt53, _a353, _b256, SingleStoreBigInt64Builder, _a354, _b257, SingleStoreBigInt64, init_bigint3, _a355, _b258, SingleStoreBinaryBuilder, _a356, _b259, SingleStoreBinary, init_binary2, _a357, _b260, SingleStoreBooleanBuilder, _a358, _b261, SingleStoreBoolean, init_boolean3, _a359, _b262, SingleStoreCharBuilder, _a360, _b263, SingleStoreChar, init_char3, _a361, _b264, SingleStoreCustomColumnBuilder, _a362, _b265, SingleStoreCustomColumn, init_custom4, _a363, _b266, SingleStoreDateBuilder, _a364, _b267, SingleStoreDate, _a365, _b268, SingleStoreDateStringBuilder, _a366, _b269, SingleStoreDateString, init_date3, _a367, _b270, SingleStoreDateTimeBuilder, _a368, _b271, SingleStoreDateTime, _a369, _b272, SingleStoreDateTimeStringBuilder, _a370, _b273, SingleStoreDateTimeString, init_datetime2, _a371, _b274, SingleStoreDecimalBuilder, _a372, _b275, SingleStoreDecimal, _a373, _b276, SingleStoreDecimalNumberBuilder, _a374, _b277, SingleStoreDecimalNumber, _a375, _b278, SingleStoreDecimalBigIntBuilder, _a376, _b279, SingleStoreDecimalBigInt, init_decimal2, _a377, _b280, SingleStoreDoubleBuilder, _a378, _b281, SingleStoreDouble, init_double2, _a379, _b282, SingleStoreEnumColumnBuilder, _a380, _b283, SingleStoreEnumColumn, init_enum3, _a381, _b284, SingleStoreFloatBuilder, _a382, _b285, SingleStoreFloat, init_float2, _a383, _b286, SingleStoreIntBuilder, _a384, _b287, SingleStoreInt, init_int2, _a385, _b288, SingleStoreJsonBuilder, _a386, _b289, SingleStoreJson, init_json3, _a387, _b290, SingleStoreMediumIntBuilder, _a388, _b291, SingleStoreMediumInt, init_mediumint2, _a389, _b292, SingleStoreRealBuilder, _a390, _b293, SingleStoreReal, init_real4, _a391, _b294, SingleStoreSerialBuilder, _a392, _b295, SingleStoreSerial, init_serial3, _a393, _b296, SingleStoreSmallIntBuilder, _a394, _b297, SingleStoreSmallInt, init_smallint3, _a395, _b298, SingleStoreTextBuilder, _a396, _b299, SingleStoreText, init_text4, _a397, _b300, SingleStoreTimeBuilder, _a398, _b301, SingleStoreTime, init_time3, _a399, _b302, SingleStoreDateColumnBaseBuilder, _a400, _b303, SingleStoreDateBaseColumn, init_date_common3, _a401, _b304, SingleStoreTimestampBuilder, _a402, _b305, SingleStoreTimestamp, _a403, _b306, SingleStoreTimestampStringBuilder, _a404, _b307, SingleStoreTimestampString, init_timestamp3, _a405, _b308, SingleStoreTinyIntBuilder, _a406, _b309, SingleStoreTinyInt, init_tinyint2, _a407, _b310, SingleStoreVarBinaryBuilder, _a408, _b311, SingleStoreVarBinary, init_varbinary2, _a409, _b312, SingleStoreVarCharBuilder, _a410, _b313, SingleStoreVarChar, init_varchar3, _a411, _b314, SingleStoreVectorBuilder, _a412, _b315, SingleStoreVector, init_vector4, _a413, _b316, SingleStoreYearBuilder, _a414, _b317, SingleStoreYear, init_year2, init_columns4, _a415, _b318, _c12, _SingleStoreCountBuilder, SingleStoreCountBuilder, init_count4, _a416, IndexBuilderOn4, _a417, IndexBuilder4, _a418, Index6, init_indexes4, init_all4, _a419, _b319, _c13, _d5, SingleStoreTable, init_table52, _a420, PrimaryKeyBuilder4, _a421, PrimaryKey4, init_primary_keys4, init_utils10, _a422, _b320, SingleStoreDeleteBase, init_delete4, _a423, SingleStoreInsertBuilder, _a424, _b321, SingleStoreInsertBase, init_insert4, _a425, SingleStoreDialect, init_dialect4, _a426, SingleStoreSelectBuilder, _a427, _b322, SingleStoreSelectQueryBuilderBase, _a428, _b323, SingleStoreSelectBase, getSingleStoreSetOperators, union5, unionAll4, intersect4, except4, minus, init_select5, _a429, QueryBuilder4, init_query_builder5, init_select_types4, _a430, SingleStoreUpdateBuilder, _a431, _b324, SingleStoreUpdateBase, init_update4, init_query_builders4, _a432, SingleStoreDatabase, init_db4, _a433, SingleStoreSchema5, init_schema32, _a434, SingleStorePreparedQuery, _a435, SingleStoreSession, _a436, _b325, SingleStoreTransaction, init_session4, init_subquery5, init_singlestore_core, dialect5, generateSingleStoreSnapshot, fromDatabase4, init_singlestoreSerializer, sqliteImports_exports, prepareFromExports2, prepareFromSqliteImports, init_sqliteImports, mysqlImports_exports, prepareFromExports3, prepareFromMySqlImports, init_mysqlImports, mysqlPushUtils_exports, import_hanji8, filterStatements, logSuggestionsAndReturn2, init_mysqlPushUtils, mysqlIntrospect_exports, import_hanji9, mysqlPushIntrospect, init_mysqlIntrospect, singlestoreImports_exports, prepareFromExports4, prepareFromSingleStoreImports, init_singlestoreImports, singlestorePushUtils_exports, import_hanji10, filterStatements2, logSuggestionsAndReturn3, init_singlestorePushUtils, singlestoreIntrospect_exports, import_hanji11, singlestorePushIntrospect, init_singlestoreIntrospect, import_hanji3, pgPushIntrospect = async (db2, filters, schemaFilters, entities, tsSchema) => {
100998
+ }, __toESM5 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target, mod)), __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value), ANSI_BACKGROUND_OFFSET, wrapAnsi16, wrapAnsi256, wrapAnsi16m, styles2, modifierNames, foregroundColorNames, backgroundColorNames, colorNames, ansiStyles, ansi_styles_default, init_ansi_styles, env, flagForceColor, supportsColor, supports_color_default, init_supports_color, init_utilities, stdoutColor, stderrColor, GENERATOR, STYLER, IS_EMPTY, levelMapping, styles22, applyOptions, chalkFactory, getModelAnsi, usedModels, proto, createStyler, createBuilder, applyStyle, chalk, chalkStderr, source_default, init_source, require_old, require_fs, require_path, require_balanced_match, require_brace_expansion, require_minimatch, require_inherits_browser2, require_inherits2, require_common3, require_sync, require_wrappy, require_once, require_inflight, require_glob, require_readline, require_src3, require_utils4, require_lodash, require_hanji, originUUID, snapshotVersion, mapValues, mapKeys, mapEntries, customMapEntries, init_global2, util3, objectUtil2, ZodParsedType2, getParsedType4, init_util4, ZodIssueCode4, ZodError5, init_ZodError2, errorMap2, en_default4, init_en4, overrideErrorMap2, init_errors9, makeIssue2, ParseStatus2, INVALID3, DIRTY2, OK2, isAborted2, isDirty2, isValid2, isAsync2, init_parseUtil2, init_typeAliases2, errorUtil2, init_errorUtil2, ParseInputLazyPath2, handleResult2, ZodType4, cuidRegex2, cuid2Regex2, ulidRegex2, uuidRegex2, nanoidRegex2, jwtRegex2, durationRegex2, emailRegex2, _emojiRegex2, emojiRegex2, ipv4Regex2, ipv4CidrRegex2, ipv6Regex2, ipv6CidrRegex2, base64Regex2, base64urlRegex2, dateRegexSource2, dateRegex2, ZodString4, ZodNumber4, ZodBigInt4, ZodBoolean4, ZodDate4, ZodSymbol4, ZodUndefined4, ZodNull4, ZodAny4, ZodUnknown4, ZodNever4, ZodVoid4, ZodArray4, ZodObject4, ZodUnion4, getDiscriminator2, ZodDiscriminatedUnion4, ZodIntersection4, ZodTuple4, ZodRecord4, ZodMap4, ZodSet4, ZodFunction3, ZodLazy4, ZodLiteral4, ZodEnum4, ZodNativeEnum2, ZodPromise4, ZodEffects2, ZodOptional4, ZodNullable4, ZodDefault4, ZodCatch4, ZodNaN4, BRAND2, ZodBranded2, ZodPipeline2, ZodReadonly4, late2, ZodFirstPartyTypeKind3, stringType2, numberType2, nanType2, bigIntType2, booleanType2, dateType2, symbolType2, undefinedType2, nullType2, anyType2, unknownType2, neverType2, voidType2, arrayType2, objectType2, strictObjectType2, unionType2, discriminatedUnionType2, intersectionType2, tupleType2, recordType2, mapType2, setType2, functionType2, lazyType2, literalType2, enumType2, nativeEnumType2, promiseType2, effectsType2, optionalType2, nullableType2, preprocessType2, pipelineType2, coerce2, init_types5, init_external4, init_v32, init_esm2, enumSchema, enumSchemaV1, indexColumn, index2, fk, sequenceSchema, roleSchema, sequenceSquashed, column2, checkConstraint, columnSquashed, compositePK, uniqueConstraint, policy, policySquashed, viewWithOption, matViewWithOption, mergedViewWithOption, view2, table8, schemaHash, kitInternals, gelSchemaExternal, gelSchemaInternal, tableSquashed, gelSchemaSquashed, gelSchema, dryGel, init_gelSchema, index22, fk2, column22, tableV3, compositePK2, uniqueConstraint2, checkConstraint2, tableV4, table22, viewMeta, view22, kitInternals2, dialect2, schemaHash2, schemaInternalV3, schemaInternalV4, schemaInternalV5, schemaInternal, schemaV3, schemaV4, schemaV5, schema2, tableSquashedV4, tableSquashed2, viewSquashed, schemaSquashed, schemaSquashedV4, MySqlSquasher, squashMysqlScheme, mysqlSchema, mysqlSchemaV5, mysqlSchemaSquashed, backwardCompatibleMysqlSchema, dryMySql, init_mysqlSchema, indexV2, columnV2, tableV2, enumSchemaV12, enumSchema2, pgSchemaV2, references, columnV1, tableV1, pgSchemaV1, indexColumn2, index3, indexV4, indexV5, indexV6, fk3, sequenceSchema2, roleSchema2, sequenceSquashed2, columnV7, column3, checkConstraint3, columnSquashed2, tableV32, compositePK3, uniqueConstraint3, policy2, policySquashed2, viewWithOption2, matViewWithOption2, mergedViewWithOption2, view3, tableV42, tableV5, tableV6, tableV7, table32, schemaHash3, kitInternals3, pgSchemaInternalV3, pgSchemaInternalV4, pgSchemaInternalV5, pgSchemaInternalV6, pgSchemaExternal, pgSchemaInternalV7, pgSchemaInternal, tableSquashed3, tableSquashedV42, pgSchemaSquashedV4, pgSchemaSquashedV6, pgSchemaSquashed, pgSchemaV3, pgSchemaV4, pgSchemaV5, pgSchemaV6, pgSchemaV7, pgSchema, backwardCompatiblePgSchema, PgSquasher, squashPgScheme, dryPg, init_pgSchema, index4, column4, compositePK4, uniqueConstraint4, table42, viewMeta2, kitInternals4, dialect22, schemaHash4, schemaInternal2, schema22, tableSquashed4, schemaSquashed2, SingleStoreSquasher, squashSingleStoreScheme, singlestoreSchema, singlestoreSchemaSquashed, backwardCompatibleSingleStoreSchema, drySingleStore, init_singlestoreSchema, index5, fk4, compositePK5, column5, tableV33, uniqueConstraint5, checkConstraint4, table52, view4, dialect3, schemaHash5, schemaInternalV32, schemaInternalV42, schemaInternalV52, kitInternals5, latestVersion, schemaInternal3, schemaV32, schemaV42, schemaV52, schema3, tableSquashed5, schemaSquashed3, SQLiteSquasher, squashSqliteScheme, drySQLite, sqliteSchemaV5, sqliteSchema, SQLiteSchemaSquashed, backwardCompatibleSqliteSchema, init_sqliteSchema, copy, prepareMigrationMeta, schemaRenameKey, tableRenameKey, columnRenameKey, init_utils7, import_hanji, warning, error88, isRenamePromptItem, ResolveColumnSelect, tableKey, ResolveSelectNamed, ResolveSelect, ResolveSchemasSelect, Spinner2, ProgressView, init_views, glob, init_serializer, fillPgSnapshot, init_migrationPreparator, require_heap, require_heap2, require_difflib, require_difflib2, require_util2, require_styles, require_has_flag2, require_supports_colors, require_trap, require_zalgo, require_america, require_zebra, require_rainbow, require_random, require_colors, require_safe, require_colorize, require_lib4, import_json_diff, mapArraysDiff, findAlternationsInTable, alternationsInColumn, init_jsonDiffer, parseType, Convertor, PgCreateRoleConvertor, PgDropRoleConvertor, PgRenameRoleConvertor, PgAlterRoleConvertor, PgCreatePolicyConvertor, PgDropPolicyConvertor, PgRenamePolicyConvertor, PgAlterPolicyConvertor, PgCreateIndPolicyConvertor, PgDropIndPolicyConvertor, PgRenameIndPolicyConvertor, PgAlterIndPolicyConvertor, PgEnableRlsConvertor, PgDisableRlsConvertor, PgCreateTableConvertor, MySqlCreateTableConvertor, SingleStoreCreateTableConvertor, SQLiteCreateTableConvertor, PgCreateViewConvertor, MySqlCreateViewConvertor, SqliteCreateViewConvertor, PgDropViewConvertor, MySqlDropViewConvertor, SqliteDropViewConvertor, MySqlAlterViewConvertor, PgRenameViewConvertor, MySqlRenameViewConvertor, PgAlterViewSchemaConvertor, PgAlterViewAddWithOptionConvertor, PgAlterViewDropWithOptionConvertor, PgAlterViewAlterTablespaceConvertor, PgAlterViewAlterUsingConvertor, PgAlterTableAlterColumnSetGenerated, PgAlterTableAlterColumnDropGenerated, PgAlterTableAlterColumnAlterGenerated, PgAlterTableAddUniqueConstraintConvertor, PgAlterTableDropUniqueConstraintConvertor, PgAlterTableAddCheckConstraintConvertor, PgAlterTableDeleteCheckConstraintConvertor, MySQLAlterTableAddUniqueConstraintConvertor, MySQLAlterTableDropUniqueConstraintConvertor, MySqlAlterTableAddCheckConstraintConvertor, SingleStoreAlterTableAddUniqueConstraintConvertor, SingleStoreAlterTableDropUniqueConstraintConvertor, MySqlAlterTableDeleteCheckConstraintConvertor, CreatePgSequenceConvertor, DropPgSequenceConvertor, RenamePgSequenceConvertor, MovePgSequenceConvertor, AlterPgSequenceConvertor, CreateTypeEnumConvertor, DropTypeEnumConvertor, AlterTypeAddValueConvertor, AlterTypeSetSchemaConvertor, AlterRenameTypeConvertor, AlterTypeDropValueConvertor, PgDropTableConvertor, MySQLDropTableConvertor, SingleStoreDropTableConvertor, SQLiteDropTableConvertor, PgRenameTableConvertor, SqliteRenameTableConvertor, MySqlRenameTableConvertor, SingleStoreRenameTableConvertor, PgAlterTableRenameColumnConvertor, MySqlAlterTableRenameColumnConvertor, SingleStoreAlterTableRenameColumnConvertor, SQLiteAlterTableRenameColumnConvertor, PgAlterTableDropColumnConvertor, MySqlAlterTableDropColumnConvertor, SingleStoreAlterTableDropColumnConvertor, SQLiteAlterTableDropColumnConvertor, PgAlterTableAddColumnConvertor, MySqlAlterTableAddColumnConvertor, SingleStoreAlterTableAddColumnConvertor, SQLiteAlterTableAddColumnConvertor, PgAlterTableAlterColumnSetTypeConvertor, PgAlterTableAlterColumnSetDefaultConvertor, PgAlterTableAlterColumnDropDefaultConvertor, PgAlterTableAlterColumnDropGeneratedConvertor, PgAlterTableAlterColumnSetExpressionConvertor, PgAlterTableAlterColumnAlterrGeneratedConvertor, SqliteAlterTableAlterColumnDropGeneratedConvertor, SqliteAlterTableAlterColumnSetExpressionConvertor, SqliteAlterTableAlterColumnAlterGeneratedConvertor, MySqlAlterTableAlterColumnAlterrGeneratedConvertor, MySqlAlterTableAddPk, MySqlAlterTableDropPk, LibSQLModifyColumn, MySqlModifyColumn, SingleStoreAlterTableAlterColumnAlterrGeneratedConvertor, SingleStoreAlterTableAddPk, SingleStoreAlterTableDropPk, SingleStoreModifyColumn, PgAlterTableCreateCompositePrimaryKeyConvertor, PgAlterTableDeleteCompositePrimaryKeyConvertor, PgAlterTableAlterCompositePrimaryKeyConvertor, MySqlAlterTableCreateCompositePrimaryKeyConvertor, MySqlAlterTableDeleteCompositePrimaryKeyConvertor, MySqlAlterTableAlterCompositePrimaryKeyConvertor, PgAlterTableAlterColumnSetPrimaryKeyConvertor, PgAlterTableAlterColumnDropPrimaryKeyConvertor, PgAlterTableAlterColumnSetNotNullConvertor, PgAlterTableAlterColumnDropNotNullConvertor, PgCreateForeignKeyConvertor, LibSQLCreateForeignKeyConvertor, MySqlCreateForeignKeyConvertor, PgAlterForeignKeyConvertor, PgDeleteForeignKeyConvertor, MySqlDeleteForeignKeyConvertor, CreatePgIndexConvertor, CreateMySqlIndexConvertor, CreateSingleStoreIndexConvertor, CreateSqliteIndexConvertor, PgDropIndexConvertor, PgCreateSchemaConvertor, PgRenameSchemaConvertor, PgDropSchemaConvertor, PgAlterTableSetSchemaConvertor, PgAlterTableSetNewSchemaConvertor, PgAlterTableRemoveFromSchemaConvertor, SqliteDropIndexConvertor, MySqlDropIndexConvertor, SingleStoreDropIndexConvertor, SQLiteRecreateTableConvertor, LibSQLRecreateTableConvertor, SingleStoreRecreateTableConvertor, convertors, init_sqlgenerator, _moveDataStatements, getOldTableName, getNewTableName, logSuggestionsAndReturn, init_sqlitePushUtils, preparePgCreateTableJson, prepareMySqlCreateTableJson, prepareSingleStoreCreateTableJson, prepareSQLiteCreateTable, prepareDropTableJson, prepareRenameTableJson, prepareCreateEnumJson, prepareAddValuesToEnumJson, prepareDropEnumValues, prepareDropEnumJson, prepareMoveEnumJson, prepareRenameEnumJson, prepareCreateSequenceJson, prepareAlterSequenceJson, prepareDropSequenceJson, prepareMoveSequenceJson, prepareRenameSequenceJson, prepareCreateRoleJson, prepareAlterRoleJson, prepareDropRoleJson, prepareRenameRoleJson, prepareCreateSchemasJson, prepareRenameSchemasJson, prepareDeleteSchemasJson, prepareRenameColumns, _prepareDropColumns, _prepareAddColumns, _prepareSqliteAddColumns, prepareAlterColumnsMysql, preparePgAlterColumns, prepareSqliteAlterColumns, prepareRenamePolicyJsons, prepareRenameIndPolicyJsons, prepareCreatePolicyJsons, prepareCreateIndPolicyJsons, prepareDropPolicyJsons, prepareDropIndPolicyJsons, prepareAlterPolicyJson, prepareAlterIndPolicyJson, preparePgCreateIndexesJson, prepareCreateIndexesJson, prepareCreateReferencesJson, prepareLibSQLCreateReferencesJson, prepareDropReferencesJson, prepareLibSQLDropReferencesJson, prepareAlterReferencesJson, prepareDropIndexesJson, prepareAddCompositePrimaryKeySqlite, prepareDeleteCompositePrimaryKeySqlite, prepareAlterCompositePrimaryKeySqlite, prepareAddCompositePrimaryKeyPg, prepareDeleteCompositePrimaryKeyPg, prepareAlterCompositePrimaryKeyPg, prepareAddUniqueConstraintPg, prepareDeleteUniqueConstraintPg, prepareAddCheckConstraint, prepareDeleteCheckConstraint, prepareAddCompositePrimaryKeyMySql, prepareDeleteCompositePrimaryKeyMySql, prepareAlterCompositePrimaryKeyMySql, preparePgCreateViewJson, prepareMySqlCreateViewJson, prepareSqliteCreateViewJson, prepareDropViewJson, prepareRenameViewJson, preparePgAlterViewAlterSchemaJson, preparePgAlterViewAddWithOptionJson, preparePgAlterViewDropWithOptionJson, preparePgAlterViewAlterTablespaceJson, preparePgAlterViewAlterUsingJson, prepareMySqlAlterView, init_jsonStatements, prepareLibSQLRecreateTable, prepareSQLiteRecreateTable, libSQLCombineStatements, sqliteCombineStatements, prepareSingleStoreRecreateTable, singleStoreCombineStatements, init_statementCombiner, snapshotsDiffer_exports, makeChanged, makeSelfOrChanged, makePatched, makeSelfOrPatched, columnSchema, alteredColumnSchema, enumSchema3, changedEnumSchema, tableScheme, alteredTableScheme, alteredViewCommon, alteredPgViewSchema, alteredMySqlViewSchema, diffResultScheme, diffResultSchemeMysql, diffResultSchemeSingleStore, diffResultSchemeSQLite, schemaChangeFor, nameChangeFor, nameSchemaChangeFor, columnChangeFor, applyPgSnapshotsDiff, applyMysqlSnapshotsDiff, applySingleStoreSnapshotsDiff, applySqliteSnapshotsDiff, applyLibSQLSnapshotsDiff, init_snapshotsDiffer, init_words, dialects, dialect4, commonSquashedSchema, commonSchema, init_schemaValidator, sqliteDriversLiterals, postgresqlDriversLiterals, prefixes, prefix, casingTypes, casingType, sqliteDriver, postgresDriver, driver2, configMigrations, configCommonSchema, casing, introspectParams, configIntrospectCliSchema, configGenerateSchema, configPushSchema, init_common2, withStyle, init_outputs, import_hanji2, schemasResolver, tablesResolver, viewsResolver, mySqlViewsResolver, sqliteViewsResolver, sequencesResolver, roleResolver, policyResolver, indPolicyResolver, enumsResolver, columnsResolver, promptColumnsConflicts, promptNamedConflict, promptNamedWithSchemasConflict, promptSchemasConflict, BREAKPOINT, init_migrate, posixClasses, braceEscape, regexpEscape, rangesToString, parseClass, init_brace_expressions, escape, init_escape, unescape, init_unescape, import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path, sep2, GLOBSTAR, plTypes, qmark, star, twoStarDot, twoStarNoDot, charSet, reSpecials, addPatternStartSet, filter, ext, defaults, braceExpand, MAX_PATTERN_LENGTH, assertValidPattern, makeRe, match2, globUnescape, globMagic, regExpEscape, Minimatch, init_mjs, entityKind2, hasOwnEntityKind2, init_entity2, _a3, Column2, init_column2, _a22, ColumnBuilder2, init_column_builder2, TableName2, init_table_utils2, _a32, ForeignKeyBuilder2, _a4, ForeignKey2, init_foreign_keys2, init_tracing_utils2, _a5, UniqueConstraintBuilder, _a6, UniqueOnConstraintBuilder, _a7, UniqueConstraint, init_unique_constraint2, init_array2, _a8, _b, PgColumnBuilder2, _a9, _b2, PgColumn2, _a10, _b3, ExtraConfigColumn2, _a11, IndexedColumn2, _a12, _b4, PgArrayBuilder2, _a13, _b5, _PgArray, PgArray2, init_common22, _a14, _b6, PgEnumObjectColumnBuilder2, _a15, _b7, PgEnumObjectColumn2, isPgEnumSym2, _a16, _b8, PgEnumColumnBuilder2, _a17, _b9, PgEnumColumn2, init_enum2, _a18, Subquery2, _a19, _b10, WithSubquery2, init_subquery2, version4, init_version2, otel2, rawTracer2, tracer2, init_tracing2, ViewBaseConfig2, init_view_common3, Schema2, Columns2, ExtraConfigColumns2, OriginalName2, BaseName2, IsAlias2, ExtraConfigBuilder2, IsDrizzleTable2, _a20, _b11, _c, _d, _e3, _f, _g, _h, _i, _j, Table2, init_table8, _a21, FakePrimitiveParam, _a222, StringChunk2, _a23, _SQL, SQL2, _a24, Name2, noopDecoder2, noopEncoder2, noopMapper2, _a25, Param2, _a26, Placeholder2, IsDrizzleView2, _a27, _b12, _c2, View3, init_sql3, _a28, ColumnAliasProxyHandler2, _a29, TableAliasProxyHandler2, _a30, RelationTableAliasProxyHandler, init_alias3, _a31, _b13, DrizzleError2, DrizzleQueryError, _a322, _b14, TransactionRollbackError2, init_errors22, _a33, ConsoleLogWriter2, _a34, DefaultLogger2, _a35, NoopLogger2, init_logger3, init_operations, _a36, _b15, QueryPromise2, init_query_promise2, textDecoder, init_utils22, _a37, _b16, PgIntColumnBaseBuilder2, init_int_common2, _a38, _b17, PgBigInt53Builder2, _a39, _b18, PgBigInt532, _a40, _b19, PgBigInt64Builder2, _a41, _b20, PgBigInt642, init_bigint2, _a42, _b21, PgBigSerial53Builder2, _a43, _b22, PgBigSerial532, _a44, _b23, PgBigSerial64Builder2, _a45, _b24, PgBigSerial642, init_bigserial2, _a46, _b25, PgBooleanBuilder2, _a47, _b26, PgBoolean2, init_boolean2, _a48, _b27, PgCharBuilder2, _a49, _b28, PgChar2, init_char2, _a50, _b29, PgCidrBuilder2, _a51, _b30, PgCidr2, init_cidr2, _a52, _b31, PgCustomColumnBuilder2, _a53, _b32, PgCustomColumn2, init_custom2, _a54, _b33, PgDateColumnBaseBuilder2, init_date_common2, _a55, _b34, PgDateBuilder2, _a56, _b35, PgDate2, _a57, _b36, PgDateStringBuilder2, _a58, _b37, PgDateString2, init_date2, _a59, _b38, PgDoublePrecisionBuilder2, _a60, _b39, PgDoublePrecision2, init_double_precision2, _a61, _b40, PgInetBuilder2, _a62, _b41, PgInet2, init_inet2, _a63, _b42, PgIntegerBuilder2, _a64, _b43, PgInteger2, init_integer2, _a65, _b44, PgIntervalBuilder2, _a66, _b45, PgInterval2, init_interval2, _a67, _b46, PgJsonBuilder2, _a68, _b47, PgJson2, init_json2, _a69, _b48, PgJsonbBuilder2, _a70, _b49, PgJsonb2, init_jsonb2, _a71, _b50, PgLineBuilder2, _a72, _b51, PgLineTuple2, _a73, _b52, PgLineABCBuilder2, _a74, _b53, PgLineABC2, init_line2, _a75, _b54, PgMacaddrBuilder2, _a76, _b55, PgMacaddr2, init_macaddr2, _a77, _b56, PgMacaddr8Builder2, _a78, _b57, PgMacaddr82, init_macaddr82, _a79, _b58, PgNumericBuilder2, _a80, _b59, PgNumeric2, _a81, _b60, PgNumericNumberBuilder2, _a82, _b61, PgNumericNumber2, _a83, _b62, PgNumericBigIntBuilder2, _a84, _b63, PgNumericBigInt2, init_numeric2, _a85, _b64, PgPointTupleBuilder2, _a86, _b65, PgPointTuple2, _a87, _b66, PgPointObjectBuilder2, _a88, _b67, PgPointObject2, init_point2, init_utils32, _a89, _b68, PgGeometryBuilder2, _a90, _b69, PgGeometry2, _a91, _b70, PgGeometryObjectBuilder2, _a92, _b71, PgGeometryObject2, init_geometry2, _a93, _b72, PgRealBuilder2, _a94, _b73, PgReal2, init_real2, _a95, _b74, PgSerialBuilder2, _a96, _b75, PgSerial2, init_serial2, _a97, _b76, PgSmallIntBuilder2, _a98, _b77, PgSmallInt2, init_smallint2, _a99, _b78, PgSmallSerialBuilder2, _a100, _b79, PgSmallSerial2, init_smallserial2, _a101, _b80, PgTextBuilder2, _a102, _b81, PgText2, init_text2, _a103, _b82, PgTimeBuilder2, _a104, _b83, PgTime2, init_time2, _a105, _b84, PgTimestampBuilder2, _a106, _b85, PgTimestamp2, _a107, _b86, PgTimestampStringBuilder2, _a108, _b87, PgTimestampString2, init_timestamp2, _a109, _b88, PgUUIDBuilder2, _a110, _b89, PgUUID2, init_uuid3, _a111, _b90, PgVarcharBuilder2, _a112, _b91, PgVarchar2, init_varchar2, _a113, _b92, PgBinaryVectorBuilder2, _a114, _b93, PgBinaryVector2, init_bit2, _a115, _b94, PgHalfVectorBuilder2, _a116, _b95, PgHalfVector2, init_halfvec2, _a117, _b96, PgSparseVectorBuilder2, _a118, _b97, PgSparseVector2, init_sparsevec2, _a119, _b98, PgVectorBuilder2, _a120, _b99, PgVector2, init_vector3, init_all2, InlineForeignKeys2, EnableRLS2, _a121, _b100, _c3, _d2, _e22, _f2, PgTable2, pgTable2, init_table22, _a122, PrimaryKeyBuilder2, _a123, PrimaryKey2, init_primary_keys2, eq2, ne4, gt3, gte2, lt4, lte2, init_conditions2, init_select3, init_expressions2, _a124, Relation2, _a125, Relations2, _a126, _b101, _One, One2, _a127, _b102, _Many, Many2, init_relations2, init_aggregate2, init_vector22, init_functions2, init_sql22, dist_exports, init_dist9, init_alias22, _a128, CheckBuilder, _a129, Check, init_checks6, init_columns2, _a130, _SelectionProxyHandler, SelectionProxyHandler2, init_selection_proxy2, _a131, IndexBuilderOn2, _a132, IndexBuilder2, _a133, Index2, init_indexes2, _a134, PgPolicy, init_policies2, PgViewConfig2, init_view_common22, _a135, CasingCache2, init_casing2, _a136, _b103, PgViewBase2, init_view_base2, _a137, PgDialect2, init_dialect2, _a138, TypedQueryBuilder2, init_query_builder3, _a139, PgSelectBuilder2, _a140, _b104, PgSelectQueryBuilderBase2, _a141, _b105, PgSelectBase2, getPgSetOperators2, union22, unionAll2, intersect2, intersectAll2, except2, exceptAll2, init_select22, _a142, QueryBuilder2, init_query_builder22, _a143, DefaultViewBuilderCore, _a144, _b106, ViewBuilder, _a145, _b107, ManualViewBuilder, _a146, MaterializedViewBuilderCore, _a147, _b108, MaterializedViewBuilder, _a148, _b109, ManualMaterializedViewBuilder, _a149, _b110, _c4, PgView2, PgMaterializedViewConfig2, _a150, _b111, _c5, PgMaterializedView, init_view2, init_utils42, _a151, _b112, PgDeleteBase2, init_delete2, _a152, PgInsertBuilder2, _a153, _b113, PgInsertBase2, init_insert2, _a154, _b114, PgRefreshMaterializedView2, init_refresh_materialized_view2, init_select_types, _a155, PgUpdateBuilder2, _a156, _b115, PgUpdateBase2, init_update2, init_query_builders2, _a157, _b116, _c6, _PgCountBuilder, PgCountBuilder2, init_count2, _a158, RelationalQueryBuilder2, _a159, _b117, PgRelationalQuery2, init_query2, _a160, _b118, PgRaw2, init_raw2, _a161, PgDatabase2, init_db2, _a162, PgRole, init_roles2, _a163, PgSequence, init_sequence2, _a164, PgSchema5, init_schema3, _a165, Cache, _a166, _b119, NoopCache, init_cache, _a167, PgPreparedQuery2, _a168, PgSession2, _a169, _b120, PgTransaction2, init_session3, init_subquery22, init_utils52, init_pg_core2, vectorOps, init_vector32, sqlToStr, init_utils62, indexName, generatePgSnapshot, trimChar, fromDatabase, defaultForColumn, getColumnsInfoQuery, init_pgSerializer, import_hanji4, Select, init_selector_ui, init_alias32, _a170, CheckBuilder2, _a171, Check2, init_checks22, _a172, ForeignKeyBuilder22, _a173, ForeignKey22, init_foreign_keys22, _a174, UniqueConstraintBuilder2, _a175, UniqueOnConstraintBuilder2, _a176, UniqueConstraint2, init_unique_constraint22, _a177, _b121, SQLiteColumnBuilder, _a178, _b122, SQLiteColumn, init_common3, _a179, _b123, SQLiteBigIntBuilder, _a180, _b124, SQLiteBigInt, _a181, _b125, SQLiteBlobJsonBuilder, _a182, _b126, SQLiteBlobJson, _a183, _b127, SQLiteBlobBufferBuilder, _a184, _b128, SQLiteBlobBuffer, init_blob, _a185, _b129, SQLiteCustomColumnBuilder, _a186, _b130, SQLiteCustomColumn, init_custom22, _a187, _b131, SQLiteBaseIntegerBuilder, _a188, _b132, SQLiteBaseInteger, _a189, _b133, SQLiteIntegerBuilder, _a190, _b134, SQLiteInteger, _a191, _b135, SQLiteTimestampBuilder, _a192, _b136, SQLiteTimestamp, _a193, _b137, SQLiteBooleanBuilder, _a194, _b138, SQLiteBoolean, init_integer22, _a195, _b139, SQLiteNumericBuilder, _a196, _b140, SQLiteNumeric, _a197, _b141, SQLiteNumericNumberBuilder, _a198, _b142, SQLiteNumericNumber, _a199, _b143, SQLiteNumericBigIntBuilder, _a200, _b144, SQLiteNumericBigInt, init_numeric22, _a201, _b145, SQLiteRealBuilder, _a202, _b146, SQLiteReal, init_real22, _a203, _b147, SQLiteTextBuilder, _a204, _b148, SQLiteText, _a205, _b149, SQLiteTextJsonBuilder, _a206, _b150, SQLiteTextJson, init_text22, init_columns22, init_all22, InlineForeignKeys22, _a207, _b151, _c7, _d3, _e32, SQLiteTable, sqliteTable, init_table32, _a208, IndexBuilderOn22, _a209, IndexBuilder22, _a210, Index4, init_indexes22, _a211, PrimaryKeyBuilder22, _a212, PrimaryKey22, init_primary_keys22, init_utils72, _a213, _b152, SQLiteDeleteBase, init_delete22, _a214, _b153, SQLiteViewBase, init_view_base22, _a215, SQLiteDialect, _a216, _b154, SQLiteSyncDialect, _a217, _b155, SQLiteAsyncDialect, init_dialect22, _a218, SQLiteSelectBuilder, _a219, _b156, SQLiteSelectQueryBuilderBase, _a220, _b157, SQLiteSelectBase, getSQLiteSetOperators, union32, unionAll22, intersect22, except22, init_select32, _a221, QueryBuilder22, init_query_builder32, _a2222, SQLiteInsertBuilder, _a223, _b158, SQLiteInsertBase, init_insert22, init_select_types2, _a224, SQLiteUpdateBuilder, _a225, _b159, SQLiteUpdateBase, init_update22, init_query_builders22, _a226, _b160, _c8, _SQLiteCountBuilder, SQLiteCountBuilder, init_count22, _a227, RelationalQueryBuilder22, _a228, _b161, SQLiteRelationalQuery, _a229, _b162, SQLiteSyncRelationalQuery, init_query22, _a230, _b163, SQLiteRaw, init_raw22, _a231, BaseSQLiteDatabase, init_db22, _a232, _b164, ExecuteResultSync, _a233, SQLitePreparedQuery, _a234, SQLiteSession, _a235, _b165, SQLiteTransaction, init_session22, init_subquery3, _a236, ViewBuilderCore, _a237, _b166, ViewBuilder2, _a238, _b167, ManualViewBuilder2, _a239, _b168, SQLiteView2, init_view22, init_sqlite_core, generateSqliteSnapshot, fromDatabase2, init_sqliteSerializer, getTablesFilterByExtensions, init_getTablesFilterByExtensions, init_alias4, _a240, CheckBuilder3, _a241, Check3, init_checks32, _a242, ForeignKeyBuilder3, _a243, ForeignKey3, init_foreign_keys3, _a244, UniqueConstraintBuilder3, _a245, UniqueOnConstraintBuilder3, _a246, UniqueConstraint3, init_unique_constraint3, _a247, _b169, MySqlColumnBuilder, _a248, _b170, MySqlColumn, _a249, _b171, MySqlColumnBuilderWithAutoIncrement, _a250, _b172, MySqlColumnWithAutoIncrement, init_common4, _a251, _b173, MySqlBigInt53Builder, _a252, _b174, MySqlBigInt53, _a253, _b175, MySqlBigInt64Builder, _a254, _b176, MySqlBigInt64, init_bigint22, _a255, _b177, MySqlBinaryBuilder, _a256, _b178, MySqlBinary, init_binary, _a257, _b179, MySqlBooleanBuilder, _a258, _b180, MySqlBoolean, init_boolean22, _a259, _b181, MySqlCharBuilder, _a260, _b182, MySqlChar, init_char22, _a261, _b183, MySqlCustomColumnBuilder, _a262, _b184, MySqlCustomColumn, init_custom3, _a263, _b185, MySqlDateBuilder, _a264, _b186, MySqlDate, _a265, _b187, MySqlDateStringBuilder, _a266, _b188, MySqlDateString, init_date22, _a267, _b189, MySqlDateTimeBuilder, _a268, _b190, MySqlDateTime, _a269, _b191, MySqlDateTimeStringBuilder, _a270, _b192, MySqlDateTimeString, init_datetime, _a271, _b193, MySqlDecimalBuilder, _a272, _b194, MySqlDecimal, _a273, _b195, MySqlDecimalNumberBuilder, _a274, _b196, MySqlDecimalNumber, _a275, _b197, MySqlDecimalBigIntBuilder, _a276, _b198, MySqlDecimalBigInt, init_decimal, _a277, _b199, MySqlDoubleBuilder, _a278, _b200, MySqlDouble, init_double, _a279, _b201, MySqlEnumColumnBuilder, _a280, _b202, MySqlEnumColumn, _a281, _b203, MySqlEnumObjectColumnBuilder, _a282, _b204, MySqlEnumObjectColumn, init_enum22, _a283, _b205, MySqlFloatBuilder, _a284, _b206, MySqlFloat, init_float, _a285, _b207, MySqlIntBuilder, _a286, _b208, MySqlInt, init_int, _a287, _b209, MySqlJsonBuilder, _a288, _b210, MySqlJson, init_json22, _a289, _b211, MySqlMediumIntBuilder, _a290, _b212, MySqlMediumInt, init_mediumint, _a291, _b213, MySqlRealBuilder, _a292, _b214, MySqlReal, init_real3, _a293, _b215, MySqlSerialBuilder, _a294, _b216, MySqlSerial, init_serial22, _a295, _b217, MySqlSmallIntBuilder, _a296, _b218, MySqlSmallInt, init_smallint22, _a297, _b219, MySqlTextBuilder, _a298, _b220, MySqlText, init_text3, _a299, _b221, MySqlTimeBuilder, _a300, _b222, MySqlTime, init_time22, _a301, _b223, MySqlDateColumnBaseBuilder, _a302, _b224, MySqlDateBaseColumn, init_date_common22, _a303, _b225, MySqlTimestampBuilder, _a304, _b226, MySqlTimestamp, _a305, _b227, MySqlTimestampStringBuilder, _a306, _b228, MySqlTimestampString, init_timestamp22, _a307, _b229, MySqlTinyIntBuilder, _a308, _b230, MySqlTinyInt, init_tinyint, _a309, _b231, MySqlVarBinaryBuilder, _a310, _b232, MySqlVarBinary, init_varbinary, _a311, _b233, MySqlVarCharBuilder, _a312, _b234, MySqlVarChar, init_varchar22, _a313, _b235, MySqlYearBuilder, _a314, _b236, MySqlYear, init_year, init_columns3, _a315, _b237, _c9, _MySqlCountBuilder, MySqlCountBuilder, init_count3, _a316, IndexBuilderOn3, _a317, IndexBuilder3, _a318, Index5, init_indexes3, init_all3, InlineForeignKeys3, _a319, _b238, _c10, _d4, _e4, MySqlTable, mysqlTable, init_table42, _a320, PrimaryKeyBuilder3, _a321, PrimaryKey3, init_primary_keys3, MySqlViewConfig, init_view_common32, init_utils8, _a3222, _b239, MySqlDeleteBase, init_delete3, _a323, _b240, MySqlViewBase, init_view_base3, _a324, MySqlDialect, init_dialect3, _a325, MySqlSelectBuilder, _a326, _b241, MySqlSelectQueryBuilderBase, _a327, _b242, MySqlSelectBase, getMySqlSetOperators, union4, unionAll3, intersect3, intersectAll22, except3, exceptAll22, init_select4, _a328, QueryBuilder3, init_query_builder4, _a329, MySqlInsertBuilder, _a330, _b243, MySqlInsertBase, init_insert3, init_select_types3, _a331, MySqlUpdateBuilder, _a332, _b244, MySqlUpdateBase, init_update3, init_query_builders3, _a333, RelationalQueryBuilder3, _a334, _b245, MySqlRelationalQuery, init_query3, _a335, MySqlDatabase, init_db3, _a336, ViewBuilderCore2, _a337, _b246, ViewBuilder3, _a338, _b247, ManualViewBuilder3, _a339, _b248, _c11, MySqlView2, init_view3, _a340, MySqlSchema5, init_schema22, _a341, MySqlPreparedQuery, _a342, MySqlSession, _a343, _b249, MySqlTransaction, init_session32, init_subquery4, init_mysql_core, handleEnumType, generateMySqlSnapshot, fromDatabase3, init_mysqlSerializer, cliConfigGenerate, pushParams, pullParams, configCheck, cliConfigCheck, init_cli, gelCredentials, init_gel, libSQLCredentials, init_libsql, mysqlCredentials, init_mysql, postgresCredentials, init_postgres, singlestoreCredentials, init_singlestore, sqliteCredentials, init_sqlite, credentials, studioCliParams, studioConfig, init_studio, es5_exports, _3, es5_default, init_es5, import_hanji7, assertES5, safeRegister, migrateConfig, init_utils9, prepareFromExports, init_pgImports, init_alias5, _a344, UniqueConstraintBuilder4, _a345, UniqueOnConstraintBuilder4, _a346, UniqueConstraint4, init_unique_constraint4, _a347, _b250, SingleStoreColumnBuilder, _a348, _b251, SingleStoreColumn, _a349, _b252, SingleStoreColumnBuilderWithAutoIncrement, _a350, _b253, SingleStoreColumnWithAutoIncrement, init_common5, _a351, _b254, SingleStoreBigInt53Builder, _a352, _b255, SingleStoreBigInt53, _a353, _b256, SingleStoreBigInt64Builder, _a354, _b257, SingleStoreBigInt64, init_bigint3, _a355, _b258, SingleStoreBinaryBuilder, _a356, _b259, SingleStoreBinary, init_binary2, _a357, _b260, SingleStoreBooleanBuilder, _a358, _b261, SingleStoreBoolean, init_boolean3, _a359, _b262, SingleStoreCharBuilder, _a360, _b263, SingleStoreChar, init_char3, _a361, _b264, SingleStoreCustomColumnBuilder, _a362, _b265, SingleStoreCustomColumn, init_custom4, _a363, _b266, SingleStoreDateBuilder, _a364, _b267, SingleStoreDate, _a365, _b268, SingleStoreDateStringBuilder, _a366, _b269, SingleStoreDateString, init_date3, _a367, _b270, SingleStoreDateTimeBuilder, _a368, _b271, SingleStoreDateTime, _a369, _b272, SingleStoreDateTimeStringBuilder, _a370, _b273, SingleStoreDateTimeString, init_datetime2, _a371, _b274, SingleStoreDecimalBuilder, _a372, _b275, SingleStoreDecimal, _a373, _b276, SingleStoreDecimalNumberBuilder, _a374, _b277, SingleStoreDecimalNumber, _a375, _b278, SingleStoreDecimalBigIntBuilder, _a376, _b279, SingleStoreDecimalBigInt, init_decimal2, _a377, _b280, SingleStoreDoubleBuilder, _a378, _b281, SingleStoreDouble, init_double2, _a379, _b282, SingleStoreEnumColumnBuilder, _a380, _b283, SingleStoreEnumColumn, init_enum3, _a381, _b284, SingleStoreFloatBuilder, _a382, _b285, SingleStoreFloat, init_float2, _a383, _b286, SingleStoreIntBuilder, _a384, _b287, SingleStoreInt, init_int2, _a385, _b288, SingleStoreJsonBuilder, _a386, _b289, SingleStoreJson, init_json3, _a387, _b290, SingleStoreMediumIntBuilder, _a388, _b291, SingleStoreMediumInt, init_mediumint2, _a389, _b292, SingleStoreRealBuilder, _a390, _b293, SingleStoreReal, init_real4, _a391, _b294, SingleStoreSerialBuilder, _a392, _b295, SingleStoreSerial, init_serial3, _a393, _b296, SingleStoreSmallIntBuilder, _a394, _b297, SingleStoreSmallInt, init_smallint3, _a395, _b298, SingleStoreTextBuilder, _a396, _b299, SingleStoreText, init_text4, _a397, _b300, SingleStoreTimeBuilder, _a398, _b301, SingleStoreTime, init_time3, _a399, _b302, SingleStoreDateColumnBaseBuilder, _a400, _b303, SingleStoreDateBaseColumn, init_date_common3, _a401, _b304, SingleStoreTimestampBuilder, _a402, _b305, SingleStoreTimestamp, _a403, _b306, SingleStoreTimestampStringBuilder, _a404, _b307, SingleStoreTimestampString, init_timestamp3, _a405, _b308, SingleStoreTinyIntBuilder, _a406, _b309, SingleStoreTinyInt, init_tinyint2, _a407, _b310, SingleStoreVarBinaryBuilder, _a408, _b311, SingleStoreVarBinary, init_varbinary2, _a409, _b312, SingleStoreVarCharBuilder, _a410, _b313, SingleStoreVarChar, init_varchar3, _a411, _b314, SingleStoreVectorBuilder, _a412, _b315, SingleStoreVector, init_vector4, _a413, _b316, SingleStoreYearBuilder, _a414, _b317, SingleStoreYear, init_year2, init_columns4, _a415, _b318, _c12, _SingleStoreCountBuilder, SingleStoreCountBuilder, init_count4, _a416, IndexBuilderOn4, _a417, IndexBuilder4, _a418, Index6, init_indexes4, init_all4, _a419, _b319, _c13, _d5, SingleStoreTable, init_table52, _a420, PrimaryKeyBuilder4, _a421, PrimaryKey4, init_primary_keys4, init_utils10, _a422, _b320, SingleStoreDeleteBase, init_delete4, _a423, SingleStoreInsertBuilder, _a424, _b321, SingleStoreInsertBase, init_insert4, _a425, SingleStoreDialect, init_dialect4, _a426, SingleStoreSelectBuilder, _a427, _b322, SingleStoreSelectQueryBuilderBase, _a428, _b323, SingleStoreSelectBase, getSingleStoreSetOperators, union5, unionAll4, intersect4, except4, minus, init_select5, _a429, QueryBuilder4, init_query_builder5, init_select_types4, _a430, SingleStoreUpdateBuilder, _a431, _b324, SingleStoreUpdateBase, init_update4, init_query_builders4, _a432, SingleStoreDatabase, init_db4, _a433, SingleStoreSchema5, init_schema32, _a434, SingleStorePreparedQuery, _a435, SingleStoreSession, _a436, _b325, SingleStoreTransaction, init_session4, init_subquery5, init_singlestore_core, dialect5, generateSingleStoreSnapshot, fromDatabase4, init_singlestoreSerializer, sqliteImports_exports, prepareFromExports2, prepareFromSqliteImports, init_sqliteImports, mysqlImports_exports, prepareFromExports3, prepareFromMySqlImports, init_mysqlImports, mysqlPushUtils_exports, import_hanji8, filterStatements, logSuggestionsAndReturn2, init_mysqlPushUtils, mysqlIntrospect_exports, import_hanji9, mysqlPushIntrospect, init_mysqlIntrospect, singlestoreImports_exports, prepareFromExports4, prepareFromSingleStoreImports, init_singlestoreImports, singlestorePushUtils_exports, import_hanji10, filterStatements2, logSuggestionsAndReturn3, init_singlestorePushUtils, singlestoreIntrospect_exports, import_hanji11, singlestorePushIntrospect, init_singlestoreIntrospect, import_hanji3, pgPushIntrospect = async (db2, filters, schemaFilters, entities, tsSchema) => {
100238
100999
  const matchers = filters.map((it3) => {
100239
101000
  return new Minimatch(it3);
100240
101001
  });
@@ -119280,8 +120041,8 @@ ${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.newC
119280
120041
  win32: { sep: "\\" },
119281
120042
  posix: { sep: "/" }
119282
120043
  };
119283
- sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
119284
- minimatch.sep = sep;
120044
+ sep2 = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
120045
+ minimatch.sep = sep2;
119285
120046
  GLOBSTAR = Symbol("globstar **");
119286
120047
  minimatch.GLOBSTAR = GLOBSTAR;
119287
120048
  plTypes = {
@@ -138183,7 +138944,7 @@ async function seedCoreGames(db2) {
138183
138944
  }
138184
138945
  async function seedCurrentProjectGame(db2, project) {
138185
138946
  const now2 = new Date;
138186
- const desiredGameId = project.gameId?.trim() || undefined;
138947
+ const desiredGameId = project.gameId?.trim() || await localGameId(project.slug);
138187
138948
  try {
138188
138949
  const existingGame = await db2.query.games.findFirst({
138189
138950
  where: (row, operators) => operators.eq(row.slug, project.slug)
@@ -138199,7 +138960,7 @@ async function seedCurrentProjectGame(db2, project) {
138199
138960
  }
138200
138961
  }
138201
138962
  const gameRecord = {
138202
- id: desiredGameId ?? crypto.randomUUID(),
138963
+ id: desiredGameId,
138203
138964
  slug: project.slug,
138204
138965
  displayName: project.displayName,
138205
138966
  version: project.version,
@@ -138234,6 +138995,7 @@ var init_games = __esm(() => {
138234
138995
  init_drizzle_orm();
138235
138996
  init_src();
138236
138997
  init_tables_index();
138998
+ init_uuid2();
138237
138999
  init_constants();
138238
139000
  init_logging();
138239
139001
  init_timeback5();
@@ -138819,19 +139581,50 @@ var init_types6 = () => {};
138819
139581
  function hasGameManagementAccess(user) {
138820
139582
  return user.role === "admin" || user.role === "teacher" || user.role === "developer" && user.developerStatus === "approved";
138821
139583
  }
139584
+ function isDashboardWorkerKey(key) {
139585
+ return Boolean(key?.permissions?.[DASHBOARD_PERMISSION_NAMESPACE]);
139586
+ }
139587
+ function workerKeyGrantsGameRead(key, slug2) {
139588
+ if (!isDashboardWorkerKey(key) && !isGameWorkerKey(key)) {
139589
+ return false;
139590
+ }
139591
+ const games2 = key?.permissions?.games;
139592
+ return Boolean(games2?.includes(`read:${slug2}`) || games2?.includes(`write:${slug2}`));
139593
+ }
139594
+ function isGameWorkerKey(key) {
139595
+ return Boolean(key?.name?.startsWith(GAME_WORKER_KEY_PREFIX));
139596
+ }
139597
+ function deniedWorkerKeyRequest(key, method, pathname) {
139598
+ if (isDashboardWorkerKey(key) && !isAllowedDashboardWorkerRequest(method, pathname, key.permissions)) {
139599
+ return DASHBOARD_WORKER_KEY_RESTRICTED;
139600
+ }
139601
+ return null;
139602
+ }
139603
+ function rejectDashboardWorkerKey(ctx) {
139604
+ if (isDashboardWorkerKey(ctx.apiKey)) {
139605
+ throw ApiError.forbidden(DASHBOARD_WORKER_KEY_RESTRICTED);
139606
+ }
139607
+ }
139608
+ function assertAuthenticatedRequest(ctx) {
139609
+ if (!isAuthenticated(ctx)) {
139610
+ throw ApiError.unauthorized("Valid session or bearer token required");
139611
+ }
139612
+ if (ctx.apiKey) {
139613
+ const denied = deniedWorkerKeyRequest(ctx.apiKey, ctx.request.method, ctx.url.pathname);
139614
+ if (denied) {
139615
+ throw ApiError.forbidden(denied);
139616
+ }
139617
+ }
139618
+ }
138822
139619
  function requireAuth(handler) {
138823
139620
  return async (ctx) => {
138824
- if (!isAuthenticated(ctx)) {
138825
- throw ApiError.unauthorized("Valid session or bearer token required");
138826
- }
139621
+ assertAuthenticatedRequest(ctx);
138827
139622
  return handler(ctx);
138828
139623
  };
138829
139624
  }
138830
139625
  function requireNonAnonymous(handler) {
138831
139626
  return async (ctx) => {
138832
- if (!isAuthenticated(ctx)) {
138833
- throw ApiError.unauthorized("Valid session or bearer token required");
138834
- }
139627
+ assertAuthenticatedRequest(ctx);
138835
139628
  if (ctx.user.isAnonymous) {
138836
139629
  throw ApiError.forbidden("This operation is not available for demo/anonymous users");
138837
139630
  }
@@ -138840,9 +139633,7 @@ function requireNonAnonymous(handler) {
138840
139633
  }
138841
139634
  function requireAnonymous(handler) {
138842
139635
  return async (ctx) => {
138843
- if (!isAuthenticated(ctx)) {
138844
- throw ApiError.unauthorized("Valid session or bearer token required");
138845
- }
139636
+ assertAuthenticatedRequest(ctx);
138846
139637
  if (!ctx.user.isAnonymous) {
138847
139638
  throw ApiError.forbidden("This operation is only available for demo/anonymous users");
138848
139639
  }
@@ -138851,9 +139642,8 @@ function requireAnonymous(handler) {
138851
139642
  }
138852
139643
  function requireAdmin(handler) {
138853
139644
  return async (ctx) => {
138854
- if (!isAuthenticated(ctx)) {
138855
- throw ApiError.unauthorized("Valid session or bearer token required");
138856
- }
139645
+ assertAuthenticatedRequest(ctx);
139646
+ rejectDashboardWorkerKey(ctx);
138857
139647
  if (ctx.user.role !== "admin") {
138858
139648
  throw ApiError.forbidden("Admin access required");
138859
139649
  }
@@ -138862,9 +139652,8 @@ function requireAdmin(handler) {
138862
139652
  }
138863
139653
  function requireDeveloper(handler) {
138864
139654
  return async (ctx) => {
138865
- if (!isAuthenticated(ctx)) {
138866
- throw ApiError.unauthorized("Valid session or bearer token required");
138867
- }
139655
+ assertAuthenticatedRequest(ctx);
139656
+ rejectDashboardWorkerKey(ctx);
138868
139657
  const isAdmin = ctx.user.role === "admin";
138869
139658
  const isApprovedDev = ctx.user.role === "developer" && ctx.user.developerStatus === "approved";
138870
139659
  if (!isAdmin && !isApprovedDev) {
@@ -138873,20 +139662,30 @@ function requireDeveloper(handler) {
138873
139662
  return handler(ctx);
138874
139663
  };
138875
139664
  }
139665
+ function requireHumanDeveloper(handler) {
139666
+ return requireDeveloper(async (ctx) => {
139667
+ if (isDashboardWorkerKey(ctx.apiKey) || isGameWorkerKey(ctx.apiKey)) {
139668
+ throw ApiError.forbidden(WORKER_KEY_HUMAN_ONLY);
139669
+ }
139670
+ return handler(ctx);
139671
+ });
139672
+ }
138876
139673
  function requireGameManagementAccess(handler) {
138877
139674
  return async (ctx) => {
138878
- if (!isAuthenticated(ctx)) {
138879
- throw ApiError.unauthorized("Valid session or bearer token required");
138880
- }
139675
+ assertAuthenticatedRequest(ctx);
139676
+ rejectDashboardWorkerKey(ctx);
138881
139677
  if (!hasGameManagementAccess(ctx.user)) {
138882
139678
  throw ApiError.forbidden("Game management access required");
138883
139679
  }
138884
139680
  return handler(ctx);
138885
139681
  };
138886
139682
  }
139683
+ var WORKER_KEY_HUMAN_ONLY = "This operation requires your own credential — platform worker keys are refused";
138887
139684
  var init_auth_util = __esm(() => {
138888
139685
  init_errors();
138889
139686
  init_types6();
139687
+ init_dashboard_util();
139688
+ init_deployment_util();
138890
139689
  });
138891
139690
 
138892
139691
  // ../api-core/src/utils/controller.util.ts
@@ -139030,6 +139829,21 @@ function requireGameId(gameId) {
139030
139829
  }
139031
139830
  return gameId;
139032
139831
  }
139832
+ function requireSlug(slug2) {
139833
+ if (!slug2) {
139834
+ throw ApiError.badRequest("Missing game slug");
139835
+ }
139836
+ return slug2;
139837
+ }
139838
+ function requireUserId(userId) {
139839
+ if (!userId) {
139840
+ throw ApiError.badRequest("Missing user ID");
139841
+ }
139842
+ if (!isValidUUID(userId)) {
139843
+ throw ApiError.unprocessableEntity("userId must be a valid UUID format");
139844
+ }
139845
+ return userId;
139846
+ }
139033
139847
  var init_params_util = __esm(() => {
139034
139848
  init_src4();
139035
139849
  init_errors();
@@ -139078,6 +139892,7 @@ var init_validation_util = __esm(() => {
139078
139892
  // ../api-core/src/utils/index.ts
139079
139893
  var init_utils11 = __esm(() => {
139080
139894
  init_auth_util();
139895
+ init_dashboard_util();
139081
139896
  init_deployment_util();
139082
139897
  init_leaderboard_util();
139083
139898
  init_lti_util();
@@ -139170,6 +139985,83 @@ var init_bucket_controller = __esm(() => {
139170
139985
  });
139171
139986
  });
139172
139987
 
139988
+ // ../api-core/src/controllers/dashboard.controller.ts
139989
+ function requireDashboardWorkerKey(ctx, slug2) {
139990
+ const scopes = ctx.apiKey?.permissions?.[DASHBOARD_PERMISSION_NAMESPACE];
139991
+ if (!scopes?.includes(dashboardCredentialScope(slug2))) {
139992
+ throw ApiError.forbidden("This endpoint requires the dashboard worker key for this game");
139993
+ }
139994
+ }
139995
+ var listUsers, addUser, issueRecoveryLink, removeUser, remove, verifyLogin, acceptInvite, revokeSessions, acceptReset, dashboard2;
139996
+ var init_dashboard_controller = __esm(() => {
139997
+ init_schemas_index();
139998
+ init_errors();
139999
+ init_utils11();
140000
+ listUsers = requireHumanDeveloper(async (ctx) => {
140001
+ const slug2 = requireSlug(ctx.params.slug);
140002
+ const users2 = await ctx.services.dashboard.listUsers(slug2, ctx.user);
140003
+ return { users: users2 };
140004
+ });
140005
+ addUser = requireHumanDeveloper(async (ctx) => {
140006
+ const slug2 = requireSlug(ctx.params.slug);
140007
+ const body2 = await parseRequestBody(ctx.request, AddGameDashboardUserSchema);
140008
+ return ctx.services.dashboard.addUser(slug2, ctx.user, body2);
140009
+ });
140010
+ issueRecoveryLink = requireHumanDeveloper(async (ctx) => {
140011
+ const slug2 = requireSlug(ctx.params.slug);
140012
+ const userId = requireUserId(ctx.params.userId);
140013
+ return ctx.services.dashboard.issueRecoveryLink(slug2, ctx.user, userId);
140014
+ });
140015
+ removeUser = requireHumanDeveloper(async (ctx) => {
140016
+ const slug2 = requireSlug(ctx.params.slug);
140017
+ const userId = requireUserId(ctx.params.userId);
140018
+ await ctx.services.dashboard.removeUser(slug2, ctx.user, userId);
140019
+ return { success: true };
140020
+ });
140021
+ remove = requireHumanDeveloper(async (ctx) => {
140022
+ const slug2 = requireSlug(ctx.params.slug);
140023
+ await ctx.services.deploy.removeDashboard(slug2, ctx.user);
140024
+ return { success: true };
140025
+ });
140026
+ verifyLogin = requireAuth(async (ctx) => {
140027
+ const slug2 = requireSlug(ctx.params.slug);
140028
+ requireDashboardWorkerKey(ctx, slug2);
140029
+ const body2 = await parseRequestBody(ctx.request, VerifyGameDashboardLoginSchema);
140030
+ const user = await ctx.services.dashboard.verifyLogin(slug2, body2);
140031
+ return { user };
140032
+ });
140033
+ acceptInvite = requireAuth(async (ctx) => {
140034
+ const slug2 = requireSlug(ctx.params.slug);
140035
+ requireDashboardWorkerKey(ctx, slug2);
140036
+ const body2 = await parseRequestBody(ctx.request, AcceptGameDashboardInviteSchema);
140037
+ const user = await ctx.services.dashboard.acceptInvite(slug2, body2);
140038
+ return { user };
140039
+ });
140040
+ revokeSessions = requireHumanDeveloper(async (ctx) => {
140041
+ const slug2 = requireSlug(ctx.params.slug);
140042
+ await ctx.services.deploy.rotateDashboardSessionSecret(slug2, ctx.user);
140043
+ return { success: true };
140044
+ });
140045
+ acceptReset = requireAuth(async (ctx) => {
140046
+ const slug2 = requireSlug(ctx.params.slug);
140047
+ requireDashboardWorkerKey(ctx, slug2);
140048
+ const body2 = await parseRequestBody(ctx.request, AcceptGameDashboardResetSchema);
140049
+ const user = await ctx.services.dashboard.acceptReset(slug2, body2);
140050
+ return { user };
140051
+ });
140052
+ dashboard2 = defineControllerNames("dashboard", {
140053
+ listUsers,
140054
+ addUser,
140055
+ removeUser,
140056
+ remove,
140057
+ issueRecoveryLink,
140058
+ revokeSessions,
140059
+ verifyLogin,
140060
+ acceptInvite,
140061
+ acceptReset
140062
+ });
140063
+ });
140064
+
139173
140065
  // ../api-core/src/controllers/database.controller.ts
139174
140066
  var reset, database;
139175
140067
  var init_database_controller = __esm(() => {
@@ -139264,7 +140156,7 @@ var init_developer_controller = __esm(() => {
139264
140156
  });
139265
140157
 
139266
140158
  // ../api-core/src/controllers/domain.controller.ts
139267
- var add, list, getStatus2, remove, domains2;
140159
+ var add, list, getStatus2, remove2, domains2;
139268
140160
  var init_domain_controller = __esm(() => {
139269
140161
  init_esm();
139270
140162
  init_schemas_index();
@@ -139313,7 +140205,7 @@ var init_domain_controller = __esm(() => {
139313
140205
  const environment = getPlatformEnvironment(ctx.config);
139314
140206
  return ctx.services.domain.getStatus(slug2, hostname4, environment, ctx.user, refresh);
139315
140207
  });
139316
- remove = requireDeveloper(async (ctx) => {
140208
+ remove2 = requireDeveloper(async (ctx) => {
139317
140209
  const slug2 = ctx.params.slug;
139318
140210
  const hostname4 = ctx.params.hostname;
139319
140211
  if (!slug2) {
@@ -139329,12 +140221,12 @@ var init_domain_controller = __esm(() => {
139329
140221
  add,
139330
140222
  list,
139331
140223
  getStatus: getStatus2,
139332
- remove
140224
+ remove: remove2
139333
140225
  });
139334
140226
  });
139335
140227
 
139336
140228
  // ../api-core/src/controllers/game-member.controller.ts
139337
- function requireUserId(userId) {
140229
+ function requireUserId2(userId) {
139338
140230
  if (!userId) {
139339
140231
  throw ApiError.badRequest("Missing user ID");
139340
140232
  }
@@ -139356,13 +140248,13 @@ var init_game_member_controller = __esm(() => {
139356
140248
  });
139357
140249
  updateMemberRole = requireNonAnonymous(async (ctx) => {
139358
140250
  const gameId = requireGameId(ctx.params.gameId);
139359
- const userId = requireUserId(ctx.params.userId);
140251
+ const userId = requireUserId2(ctx.params.userId);
139360
140252
  const body2 = await parseRequestBody(ctx.request, UpdateGameMemberRoleSchema);
139361
140253
  return ctx.services.gameMember.updateRole(gameId, userId, ctx.user, body2);
139362
140254
  });
139363
140255
  removeMember = requireNonAnonymous(async (ctx) => {
139364
140256
  const gameId = requireGameId(ctx.params.gameId);
139365
- const userId = requireUserId(ctx.params.userId);
140257
+ const userId = requireUserId2(ctx.params.userId);
139366
140258
  await ctx.services.gameMember.remove(gameId, userId, ctx.user);
139367
140259
  });
139368
140260
  searchUsersForMember = requireNonAnonymous(async (ctx) => {
@@ -139380,12 +140272,13 @@ var init_game_member_controller = __esm(() => {
139380
140272
  });
139381
140273
 
139382
140274
  // ../api-core/src/controllers/game.controller.ts
139383
- var list2, listAccessible, getSubjects, getTimebackSummaries, getById, getBySlug, getManifest, upsertBySlug, patchGameMetadata, remove2, games2;
140275
+ var list2, listAccessible, getSubjects, getTimebackSummaries, getById, getBySlug, getManifest, upsertBySlug, patchGameMetadata, remove3, games2;
139384
140276
  var init_game_controller = __esm(() => {
139385
140277
  init_esm();
139386
140278
  init_schemas_index();
139387
140279
  init_errors();
139388
140280
  init_utils11();
140281
+ init_auth_util();
139389
140282
  list2 = requireNonAnonymous(async (ctx) => ctx.services.game.list(ctx.user));
139390
140283
  listAccessible = requireNonAnonymous(async (ctx) => ctx.services.game.listAccessible(ctx.user));
139391
140284
  getSubjects = requireNonAnonymous(async (ctx) => ctx.services.game.getSubjects());
@@ -139399,7 +140292,9 @@ var init_game_controller = __esm(() => {
139399
140292
  if (!slug2) {
139400
140293
  throw ApiError.badRequest("Missing game slug");
139401
140294
  }
139402
- return ctx.services.game.getBySlug(slug2, ctx.user);
140295
+ return ctx.services.game.getBySlug(slug2, ctx.user, {
140296
+ scopeAuthorized: workerKeyGrantsGameRead(ctx.apiKey, slug2)
140297
+ });
139403
140298
  });
139404
140299
  getManifest = requireNonAnonymous(async (ctx) => {
139405
140300
  const gameId = requireGameId(ctx.params.gameId);
@@ -139429,7 +140324,7 @@ var init_game_controller = __esm(() => {
139429
140324
  const body2 = await parseRequestBody(ctx.request, PatchGameMetadataSchema);
139430
140325
  return ctx.services.game.updateMetadata(gameId, body2, ctx.user);
139431
140326
  });
139432
- remove2 = requireNonAnonymous(async (ctx) => {
140327
+ remove3 = requireNonAnonymous(async (ctx) => {
139433
140328
  const gameId = requireGameId(ctx.params.gameId);
139434
140329
  await ctx.services.game.delete(gameId, ctx.user);
139435
140330
  });
@@ -139443,7 +140338,7 @@ var init_game_controller = __esm(() => {
139443
140338
  getBySlug,
139444
140339
  upsertBySlug,
139445
140340
  patchGameMetadata,
139446
- remove: remove2
140341
+ remove: remove3
139447
140342
  });
139448
140343
  });
139449
140344
 
@@ -140597,6 +141492,7 @@ var init_verify_controller = __esm(() => {
140597
141492
  // ../api-core/src/controllers/index.ts
140598
141493
  var init_controllers = __esm(() => {
140599
141494
  init_bucket_controller();
141495
+ init_dashboard_controller();
140600
141496
  init_database_controller();
140601
141497
  init_deploy_controller();
140602
141498
  init_developer_controller();