@playcademy/vite-plugin 0.0.1-beta.7 → 0.0.1-beta.9

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/index.js CHANGED
@@ -566,7 +566,7 @@ globstar while`, file, fr, pattern, pr3, swallowee);
566
566
  }
567
567
  };
568
568
  for (let i3 = 0, c2;i3 < pattern.length && (c2 = pattern.charAt(i3)); i3++) {
569
- this.debug("%s\t%s %s %j", pattern, i3, re3, c2);
569
+ this.debug("%s %s %s %j", pattern, i3, re3, c2);
570
570
  if (escaping) {
571
571
  if (c2 === "/") {
572
572
  return false;
@@ -56378,7 +56378,7 @@ globstar while`, file, fr, pattern, pr3, swallowee);
56378
56378
  }
56379
56379
  };
56380
56380
  for (let i3 = 0, c2;i3 < pattern.length && (c2 = pattern.charAt(i3)); i3++) {
56381
- this.debug("%s\t%s %s %j", pattern, i3, re3, c2);
56381
+ this.debug("%s %s %s %j", pattern, i3, re3, c2);
56382
56382
  if (escaping) {
56383
56383
  if (c2 === "/") {
56384
56384
  return false;
@@ -64901,7 +64901,7 @@ Is ${source_default.bold.blue(this.base.name)} schema created or renamed from an
64901
64901
  IS_LINE_JUNK = function(line22, pat = /^\s*#?\s*$/) {
64902
64902
  return pat.test(line22);
64903
64903
  };
64904
- IS_CHARACTER_JUNK = function(ch, ws = " \t") {
64904
+ IS_CHARACTER_JUNK = function(ch, ws = " ") {
64905
64905
  return indexOf.call(ws, ch) >= 0;
64906
64906
  };
64907
64907
  _formatRangeUnified = function(start2, stop2) {
@@ -74491,7 +74491,7 @@ globstar while`, file, fr, pattern, pr3, swallowee);
74491
74491
  }
74492
74492
  };
74493
74493
  for (let i3 = 0, c2;i3 < pattern.length && (c2 = pattern.charAt(i3)); i3++) {
74494
- this.debug("%s\t%s %s %j", pattern, i3, re3, c2);
74494
+ this.debug("%s %s %s %j", pattern, i3, re3, c2);
74495
74495
  if (escaping) {
74496
74496
  if (c2 === "/") {
74497
74497
  return false;
@@ -94242,8 +94242,8 @@ var DEMO_USER = {
94242
94242
  email: "demo@playcademy.com",
94243
94243
  emailVerified: true,
94244
94244
  image: null,
94245
- role: "player",
94246
- developerStatus: "none",
94245
+ role: "developer",
94246
+ developerStatus: "approved",
94247
94247
  createdAt: now,
94248
94248
  updatedAt: now
94249
94249
  };
@@ -113959,6 +113959,8 @@ __export(exports_schemas, {
113959
113959
  verification: () => verification,
113960
113960
  users: () => users,
113961
113961
  userRoleEnum: () => userRoleEnum,
113962
+ userLevelsRelations: () => userLevelsRelations,
113963
+ userLevels: () => userLevels,
113962
113964
  shopListingsRelations: () => shopListingsRelations,
113963
113965
  shopListings: () => shopListings,
113964
113966
  sessions: () => sessions,
@@ -113966,6 +113968,7 @@ __export(exports_schemas, {
113966
113968
  maps: () => maps,
113967
113969
  mapElementsRelations: () => mapElementsRelations,
113968
113970
  mapElements: () => mapElements,
113971
+ levelConfigs: () => levelConfigs,
113969
113972
  itemsRelations: () => itemsRelations,
113970
113973
  items: () => items,
113971
113974
  itemTypeEnum: () => itemTypeEnum,
@@ -113982,11 +113985,14 @@ __export(exports_schemas, {
113982
113985
  currenciesRelations: () => currenciesRelations,
113983
113986
  currencies: () => currencies,
113984
113987
  accounts: () => accounts,
113988
+ XPActionInputSchema: () => XPActionInputSchema,
113985
113989
  VersionSchema: () => VersionSchema,
113986
113990
  UpsertGameMetadataSchema: () => UpsertGameMetadataSchema,
113987
113991
  UpdateUserSchema: () => UpdateUserSchema,
113992
+ UpdateUserLevelSchema: () => UpdateUserLevelSchema,
113988
113993
  UpdateShopListingSchema: () => UpdateShopListingSchema,
113989
113994
  UpdateMapElementSchema: () => UpdateMapElementSchema,
113995
+ UpdateLevelConfigSchema: () => UpdateLevelConfigSchema,
113990
113996
  UpdateItemSchema: () => UpdateItemSchema,
113991
113997
  UpdateInventoryItemSchema: () => UpdateInventoryItemSchema,
113992
113998
  UpdateGameStateSchema: () => UpdateGameStateSchema,
@@ -113997,10 +114003,12 @@ __export(exports_schemas, {
113997
114003
  StartSessionInputSchema: () => StartSessionInputSchema,
113998
114004
  SelectVerificationSchema: () => SelectVerificationSchema,
113999
114005
  SelectUserSchema: () => SelectUserSchema,
114006
+ SelectUserLevelSchema: () => SelectUserLevelSchema,
114000
114007
  SelectShopListingSchema: () => SelectShopListingSchema,
114001
114008
  SelectSessionSchema: () => SelectSessionSchema,
114002
114009
  SelectMapSchema: () => SelectMapSchema,
114003
114010
  SelectMapElementSchema: () => SelectMapElementSchema,
114011
+ SelectLevelConfigSchema: () => SelectLevelConfigSchema,
114004
114012
  SelectItemSchema: () => SelectItemSchema,
114005
114013
  SelectInventoryItemSchema: () => SelectInventoryItemSchema,
114006
114014
  SelectGameStateSchema: () => SelectGameStateSchema,
@@ -114012,13 +114020,16 @@ __export(exports_schemas, {
114012
114020
  ProcessZipSchema: () => ProcessZipSchema,
114013
114021
  MapElementMetadataZodSchema: () => MapElementMetadataZodSchema,
114014
114022
  ManifestV1Schema: () => ManifestV1Schema,
114023
+ MAX_LEVEL: () => MAX_LEVEL,
114015
114024
  ItemMetadataSchema: () => ItemMetadataSchema,
114016
114025
  InventoryActionInputSchema: () => InventoryActionInputSchema,
114017
114026
  InsertVerificationSchema: () => InsertVerificationSchema,
114018
114027
  InsertUserSchema: () => InsertUserSchema,
114028
+ InsertUserLevelSchema: () => InsertUserLevelSchema,
114019
114029
  InsertShopListingSchema: () => InsertShopListingSchema,
114020
114030
  InsertSessionSchema: () => InsertSessionSchema,
114021
114031
  InsertMapElementSchema: () => InsertMapElementSchema,
114032
+ InsertLevelConfigSchema: () => InsertLevelConfigSchema,
114022
114033
  InsertItemSchema: () => InsertItemSchema,
114023
114034
  InsertInventoryItemSchema: () => InsertInventoryItemSchema,
114024
114035
  InsertGameStateSchema: () => InsertGameStateSchema,
@@ -118773,6 +118784,53 @@ var InsertShopListingSchema = createInsertSchema(shopListings, {
118773
118784
  }).omit({ id: true, createdAt: true, updatedAt: true });
118774
118785
  var SelectShopListingSchema = createSelectSchema(shopListings);
118775
118786
  var UpdateShopListingSchema = InsertShopListingSchema.partial().extend({});
118787
+ var MAX_LEVEL = 100;
118788
+ var userLevels = pgTable("user_levels", {
118789
+ userId: text("user_id").primaryKey().references(() => users.id, { onDelete: "cascade" }),
118790
+ currentLevel: integer("current_level").notNull().default(1),
118791
+ currentXp: integer("current_xp").notNull().default(0),
118792
+ totalXpEarned: integer("total_xp_earned").notNull().default(0),
118793
+ lastLevelUpAt: timestamp("last_level_up_at", { withTimezone: true }),
118794
+ createdAt: timestamp("created_at").defaultNow().notNull(),
118795
+ updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
118796
+ });
118797
+ var levelConfigs = pgTable("level_configs", {
118798
+ id: uuid("id").primaryKey().defaultRandom(),
118799
+ level: integer("level").notNull().unique(),
118800
+ xpRequired: integer("xp_required").notNull(),
118801
+ creditsReward: integer("credits_reward").notNull().default(0),
118802
+ createdAt: timestamp("created_at").defaultNow().notNull()
118803
+ }, (table6) => [uniqueIndex("unique_level_config_idx").on(table6.level)]);
118804
+ var userLevelsRelations = relations(userLevels, ({ one }) => ({
118805
+ user: one(users, {
118806
+ fields: [userLevels.userId],
118807
+ references: [users.id]
118808
+ })
118809
+ }));
118810
+ var InsertUserLevelSchema = createInsertSchema(userLevels, {
118811
+ userId: exports_external.string().min(1, "User ID is required"),
118812
+ currentLevel: exports_external.number().int().min(1, "Level must be at least 1").default(1),
118813
+ currentXp: exports_external.number().int().min(0, "XP cannot be negative").default(0),
118814
+ totalXpEarned: exports_external.number().int().min(0, "Total XP earned cannot be negative").default(0)
118815
+ }).omit({ createdAt: true, updatedAt: true });
118816
+ var SelectUserLevelSchema = createSelectSchema(userLevels);
118817
+ var UpdateUserLevelSchema = createUpdateSchema(userLevels).omit({
118818
+ userId: true,
118819
+ createdAt: true
118820
+ });
118821
+ var InsertLevelConfigSchema = createInsertSchema(levelConfigs, {
118822
+ level: exports_external.number().int().min(1, "Level must be at least 1"),
118823
+ xpRequired: exports_external.number().int().min(0, "XP required cannot be negative"),
118824
+ creditsReward: exports_external.number().int().min(0, "Credits reward cannot be negative").default(0)
118825
+ }).omit({ id: true, createdAt: true });
118826
+ var SelectLevelConfigSchema = createSelectSchema(levelConfigs);
118827
+ var UpdateLevelConfigSchema = createUpdateSchema(levelConfigs).omit({
118828
+ id: true,
118829
+ createdAt: true
118830
+ });
118831
+ var XPActionInputSchema = exports_external.object({
118832
+ amount: exports_external.number().int("XP amount must be an integer").positive("XP amount must be positive")
118833
+ });
118776
118834
 
118777
118835
  class DatabasePathManager {
118778
118836
  static DEFAULT_DB_SUBPATH = join2("@playcademy", "vite-plugin", "node_modules", ".playcademy", "sandbox.db");
@@ -118845,12 +118903,35 @@ async function seedDemoData(db) {
118845
118903
  for (const inventory2 of SAMPLE_INVENTORY) {
118846
118904
  await db.insert(inventoryItems).values(inventory2);
118847
118905
  }
118906
+ const levelConfigsData = generateLevelConfigs();
118907
+ for (const config of levelConfigsData) {
118908
+ await db.insert(levelConfigs).values(config);
118909
+ }
118848
118910
  } catch (error2) {
118849
118911
  console.error("❌ Error seeding demo data:", error2);
118850
118912
  throw error2;
118851
118913
  }
118852
118914
  return DEMO_USER;
118853
118915
  }
118916
+ function generateLevelConfigs() {
118917
+ const configs = [];
118918
+ for (let level = 1;level <= 100; level++) {
118919
+ const xpRequired = level === 1 ? 0 : Math.floor(50 * Math.pow(level - 1, 1.7));
118920
+ let creditsReward = 0;
118921
+ if (level > 1) {
118922
+ creditsReward = 25 + level * 25;
118923
+ if (level % 10 === 1 && level > 1) {
118924
+ creditsReward += 75;
118925
+ }
118926
+ }
118927
+ configs.push({
118928
+ level,
118929
+ xpRequired,
118930
+ creditsReward
118931
+ });
118932
+ }
118933
+ return configs;
118934
+ }
118854
118935
  async function seedCurrentProjectGame(db, project) {
118855
118936
  const now2 = new Date;
118856
118937
  try {
@@ -118885,7 +118966,7 @@ async function seedCurrentProjectGame(db, project) {
118885
118966
  }
118886
118967
  var package_default = {
118887
118968
  name: "@playcademy/sandbox",
118888
- version: "0.1.0-beta.2",
118969
+ version: "0.1.0-beta.3",
118889
118970
  description: "Local development server for Playcademy game development",
118890
118971
  type: "module",
118891
118972
  exports: {
@@ -118984,6 +119065,267 @@ async function getUserMe(ctx) {
118984
119065
  throw ApiError.internal("Internal server error", error2);
118985
119066
  }
118986
119067
  }
119068
+ var levelConfigCache = null;
119069
+ async function getLevelConfig(db, level) {
119070
+ if (level < 1) {
119071
+ throw ApiError.badRequest("Level must be at least 1");
119072
+ }
119073
+ if (levelConfigCache?.has(level)) {
119074
+ return levelConfigCache.get(level) || null;
119075
+ }
119076
+ try {
119077
+ const [config] = await db.select().from(levelConfigs).where(eq(levelConfigs.level, level)).limit(1);
119078
+ if (levelConfigCache && config) {
119079
+ levelConfigCache.set(level, config);
119080
+ }
119081
+ return config || null;
119082
+ } catch (error2) {
119083
+ logger2.error(`Error fetching level config for level ${level}:`, error2);
119084
+ throw ApiError.internal("Internal server error", error2);
119085
+ }
119086
+ }
119087
+ async function calculateXPToNextLevel(db, currentLevel, currentXp) {
119088
+ try {
119089
+ const nextLevelConfig = await getLevelConfig(db, currentLevel + 1);
119090
+ if (!nextLevelConfig) {
119091
+ return 0;
119092
+ }
119093
+ return Math.max(0, nextLevelConfig.xpRequired - currentXp);
119094
+ } catch (error2) {
119095
+ logger2.error(`Error calculating XP to next level:`, error2);
119096
+ throw ApiError.internal("Internal server error", error2);
119097
+ }
119098
+ }
119099
+ async function checkLevelUp(tx, currentLevel, newXp) {
119100
+ let level = currentLevel;
119101
+ let remainingXp = newXp;
119102
+ let totalCreditsAwarded = 0;
119103
+ let leveledUp = false;
119104
+ while (true) {
119105
+ if (level >= MAX_LEVEL) {
119106
+ break;
119107
+ }
119108
+ const nextLevelConfig2 = await tx.select().from(levelConfigs).where(eq(levelConfigs.level, level + 1)).limit(1);
119109
+ const [nextLevel2] = nextLevelConfig2;
119110
+ if (!nextLevel2) {
119111
+ break;
119112
+ }
119113
+ if (remainingXp >= nextLevel2.xpRequired) {
119114
+ level += 1;
119115
+ remainingXp -= nextLevel2.xpRequired;
119116
+ totalCreditsAwarded += nextLevel2.creditsReward;
119117
+ leveledUp = true;
119118
+ } else {
119119
+ break;
119120
+ }
119121
+ }
119122
+ const nextLevelConfig = await tx.select().from(levelConfigs).where(eq(levelConfigs.level, level + 1)).limit(1);
119123
+ const [nextLevel] = nextLevelConfig;
119124
+ const xpToNextLevel = nextLevel ? Math.max(0, nextLevel.xpRequired - remainingXp) : 0;
119125
+ return {
119126
+ newLevel: level,
119127
+ remainingXp,
119128
+ leveledUp,
119129
+ creditsAwarded: totalCreditsAwarded,
119130
+ xpToNextLevel
119131
+ };
119132
+ }
119133
+ function formatValidationErrors(error2) {
119134
+ const flattened = error2.flatten();
119135
+ const fieldErrors = Object.entries(flattened.fieldErrors).map(([field, errors2]) => `${field}: ${errors2?.join(", ") || "Invalid"}`).join("; ");
119136
+ const formErrors = flattened.formErrors.join("; ");
119137
+ const allErrors = [fieldErrors, formErrors].filter(Boolean).join("; ");
119138
+ return allErrors || "Validation failed";
119139
+ }
119140
+ var AddXPSchema = XPActionInputSchema;
119141
+ async function getUserLevel(ctx) {
119142
+ const user = ctx.user;
119143
+ if (!user) {
119144
+ throw ApiError.unauthorized("Valid session or bearer token required");
119145
+ }
119146
+ try {
119147
+ const db = getDatabase();
119148
+ let [userLevel] = await db.select().from(userLevels).where(eq(userLevels.userId, user.id)).limit(1);
119149
+ if (!userLevel) {
119150
+ const [newUserLevel] = await db.insert(userLevels).values({
119151
+ userId: user.id,
119152
+ currentLevel: 1,
119153
+ currentXp: 0,
119154
+ totalXpEarned: 0
119155
+ }).returning();
119156
+ if (!newUserLevel) {
119157
+ throw ApiError.internal("Failed to create user level record");
119158
+ }
119159
+ userLevel = newUserLevel;
119160
+ }
119161
+ return userLevel;
119162
+ } catch (error2) {
119163
+ if (error2 instanceof ApiError) {
119164
+ throw error2;
119165
+ }
119166
+ logger2.error(`Error fetching user level for user ${user.id}:`, error2);
119167
+ throw ApiError.internal("Internal server error", error2);
119168
+ }
119169
+ }
119170
+ async function addXP(ctx, amount) {
119171
+ const user = ctx.user;
119172
+ if (!user) {
119173
+ throw ApiError.unauthorized("Valid session or bearer token required");
119174
+ }
119175
+ if (user.role !== "developer") {
119176
+ throw ApiError.forbidden("Only developers can award XP to users");
119177
+ }
119178
+ if (amount <= 0) {
119179
+ throw ApiError.badRequest("XP amount must be positive");
119180
+ }
119181
+ try {
119182
+ const db = getDatabase();
119183
+ const result = await db.transaction(async (tx) => {
119184
+ let [userLevel] = await tx.select().from(userLevels).where(eq(userLevels.userId, user.id)).limit(1);
119185
+ if (!userLevel) {
119186
+ const [newUserLevel] = await tx.insert(userLevels).values({
119187
+ userId: user.id,
119188
+ currentLevel: 1,
119189
+ currentXp: 0,
119190
+ totalXpEarned: 0
119191
+ }).returning();
119192
+ if (!newUserLevel) {
119193
+ throw ApiError.internal("Failed to create user level record");
119194
+ }
119195
+ userLevel = newUserLevel;
119196
+ }
119197
+ const newCurrentXp = userLevel.currentXp + amount;
119198
+ const newTotalXpEarned = userLevel.totalXpEarned + amount;
119199
+ const levelUpResult = await checkLevelUp(tx, userLevel.currentLevel, newCurrentXp);
119200
+ const [updatedUserLevel] = await tx.update(userLevels).set({
119201
+ currentLevel: levelUpResult.newLevel,
119202
+ currentXp: levelUpResult.remainingXp,
119203
+ totalXpEarned: newTotalXpEarned,
119204
+ lastLevelUpAt: levelUpResult.leveledUp ? new Date : userLevel.lastLevelUpAt
119205
+ }).where(eq(userLevels.userId, user.id)).returning();
119206
+ if (!updatedUserLevel) {
119207
+ throw ApiError.internal("Failed to update user level");
119208
+ }
119209
+ let creditsAwarded = 0;
119210
+ if (levelUpResult.leveledUp) {
119211
+ const creditsToAward = levelUpResult.creditsAwarded;
119212
+ logger2.debug("User leveled up", {
119213
+ userId: user.id,
119214
+ oldLevel: userLevel.currentLevel,
119215
+ newLevel: levelUpResult.newLevel,
119216
+ xpAdded: amount,
119217
+ totalXpEarned: newTotalXpEarned,
119218
+ creditsAwarded: creditsToAward
119219
+ });
119220
+ if (creditsToAward > 0) {
119221
+ const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.internalName, "PLAYCADEMY_CREDITS")).limit(1);
119222
+ if (!creditsItem) {
119223
+ throw ApiError.internal("PLAYCADEMY_CREDITS item not found");
119224
+ }
119225
+ await tx.insert(inventoryItems).values({
119226
+ userId: user.id,
119227
+ itemId: creditsItem.id,
119228
+ quantity: creditsToAward
119229
+ }).onConflictDoUpdate({
119230
+ target: [
119231
+ inventoryItems.userId,
119232
+ inventoryItems.itemId
119233
+ ],
119234
+ set: {
119235
+ quantity: sql`${inventoryItems.quantity} + ${creditsToAward}`
119236
+ }
119237
+ });
119238
+ }
119239
+ creditsAwarded = creditsToAward;
119240
+ } else {
119241
+ logger2.debug("XP added to user", {
119242
+ userId: user.id,
119243
+ level: userLevel.currentLevel,
119244
+ xpAdded: amount,
119245
+ totalXpEarned: newTotalXpEarned
119246
+ });
119247
+ }
119248
+ return {
119249
+ totalXpEarned: newTotalXpEarned,
119250
+ newLevel: levelUpResult.newLevel,
119251
+ leveledUp: levelUpResult.leveledUp,
119252
+ creditsAwarded,
119253
+ xpToNextLevel: levelUpResult.xpToNextLevel
119254
+ };
119255
+ });
119256
+ return result;
119257
+ } catch (error2) {
119258
+ if (error2 instanceof ApiError) {
119259
+ throw error2;
119260
+ }
119261
+ logger2.error(`Error adding XP for user ${user.id}:`, error2);
119262
+ throw ApiError.internal("Internal server error", error2);
119263
+ }
119264
+ }
119265
+ async function addXPFromRequest(ctx) {
119266
+ let amount;
119267
+ try {
119268
+ const requestBody = await ctx.request.json();
119269
+ const parsed = AddXPSchema.parse(requestBody);
119270
+ amount = parsed.amount;
119271
+ } catch (error2) {
119272
+ if (error2 instanceof ZodError) {
119273
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(error2)}`);
119274
+ }
119275
+ logger2.error("Failed to parse request body:", error2);
119276
+ throw ApiError.badRequest("Invalid JSON body");
119277
+ }
119278
+ return await addXP(ctx, amount);
119279
+ }
119280
+ async function getAllLevelConfigs(_ctx) {
119281
+ try {
119282
+ const db = getDatabase();
119283
+ const configs = await db.select().from(levelConfigs).orderBy(levelConfigs.level);
119284
+ return configs;
119285
+ } catch (error2) {
119286
+ logger2.error("Error fetching all level configs:", error2);
119287
+ throw ApiError.internal("Internal server error", error2);
119288
+ }
119289
+ }
119290
+ async function getUserLevelProgress(ctx) {
119291
+ const userLevel = await getUserLevel(ctx);
119292
+ try {
119293
+ const db = getDatabase();
119294
+ const xpToNextLevel = await calculateXPToNextLevel(db, userLevel.currentLevel, userLevel.currentXp);
119295
+ return {
119296
+ level: userLevel.currentLevel,
119297
+ currentXp: userLevel.currentXp,
119298
+ xpToNextLevel,
119299
+ totalXpEarned: userLevel.totalXpEarned
119300
+ };
119301
+ } catch (error2) {
119302
+ if (error2 instanceof ApiError) {
119303
+ throw error2;
119304
+ }
119305
+ logger2.error(`Error fetching user level progress:`, error2);
119306
+ throw ApiError.internal("Internal server error", error2);
119307
+ }
119308
+ }
119309
+ async function getLevelConfigByPath(ctx) {
119310
+ const levelParam = ctx.params.level;
119311
+ if (!levelParam) {
119312
+ throw ApiError.badRequest("Level parameter is required");
119313
+ }
119314
+ const level = parseInt(levelParam, 10);
119315
+ if (isNaN(level) || level < 1) {
119316
+ throw ApiError.badRequest("Level must be a positive integer");
119317
+ }
119318
+ try {
119319
+ const db = getDatabase();
119320
+ return await getLevelConfig(db, level);
119321
+ } catch (error2) {
119322
+ if (error2 instanceof ApiError) {
119323
+ throw error2;
119324
+ }
119325
+ logger2.error(`Error fetching level config for level ${level}:`, error2);
119326
+ throw ApiError.internal("Internal server error", error2);
119327
+ }
119328
+ }
118987
119329
  var usersRouter = new Hono2;
118988
119330
  usersRouter.get("/me", async (c2) => {
118989
119331
  const ctx = {
@@ -119004,15 +119346,65 @@ usersRouter.get("/me", async (c2) => {
119004
119346
  return c2.json({ error: message }, 500);
119005
119347
  }
119006
119348
  });
119349
+ usersRouter.get("/level", async (c2) => {
119350
+ const ctx = {
119351
+ user: c2.get("user"),
119352
+ params: {},
119353
+ url: new URL(c2.req.url),
119354
+ request: c2.req.raw
119355
+ };
119356
+ try {
119357
+ const levelData = await getUserLevel(ctx);
119358
+ return c2.json(levelData);
119359
+ } catch (error2) {
119360
+ if (error2 instanceof ApiError) {
119361
+ return c2.json({ error: error2.message }, error2.statusCode);
119362
+ }
119363
+ console.error("Error in getUserLevel:", error2);
119364
+ const message = error2 instanceof Error ? error2.message : "Internal server error";
119365
+ return c2.json({ error: message }, 500);
119366
+ }
119367
+ });
119368
+ usersRouter.get("/level/progress", async (c2) => {
119369
+ const ctx = {
119370
+ user: c2.get("user"),
119371
+ params: {},
119372
+ url: new URL(c2.req.url),
119373
+ request: c2.req.raw
119374
+ };
119375
+ try {
119376
+ const progressData = await getUserLevelProgress(ctx);
119377
+ return c2.json(progressData);
119378
+ } catch (error2) {
119379
+ if (error2 instanceof ApiError) {
119380
+ return c2.json({ error: error2.message }, error2.statusCode);
119381
+ }
119382
+ console.error("Error in getUserLevelProgress:", error2);
119383
+ const message = error2 instanceof Error ? error2.message : "Internal server error";
119384
+ return c2.json({ error: message }, 500);
119385
+ }
119386
+ });
119387
+ usersRouter.post("/xp/add", async (c2) => {
119388
+ const ctx = {
119389
+ user: c2.get("user"),
119390
+ params: {},
119391
+ url: new URL(c2.req.url),
119392
+ request: c2.req.raw
119393
+ };
119394
+ try {
119395
+ const result = await addXPFromRequest(ctx);
119396
+ return c2.json(result);
119397
+ } catch (error2) {
119398
+ if (error2 instanceof ApiError) {
119399
+ return c2.json({ error: error2.message }, error2.statusCode);
119400
+ }
119401
+ console.error("Error in addXPFromRequest:", error2);
119402
+ const message = error2 instanceof Error ? error2.message : "Internal server error";
119403
+ return c2.json({ error: message }, 500);
119404
+ }
119405
+ });
119007
119406
  var healthRouter = new Hono2;
119008
119407
  healthRouter.get("/", (c2) => c2.json({ status: "ok", timestamp: new Date().toISOString() }));
119009
- function formatValidationErrors(error2) {
119010
- const flattened = error2.flatten();
119011
- const fieldErrors = Object.entries(flattened.fieldErrors).map(([field, errors2]) => `${field}: ${errors2?.join(", ") || "Invalid"}`).join("; ");
119012
- const formErrors = flattened.formErrors.join("; ");
119013
- const allErrors = [fieldErrors, formErrors].filter(Boolean).join("; ");
119014
- return allErrors || "Validation failed";
119015
- }
119016
119408
  async function getUserInventory(ctx) {
119017
119409
  const user = ctx.user;
119018
119410
  if (!user) {
@@ -123133,6 +123525,45 @@ devRouter.delete("/keys/:keyId", async (c2) => {
123133
123525
  return c2.json({ error: message2 }, 500);
123134
123526
  }
123135
123527
  });
123528
+ var levelsRouter = new Hono2;
123529
+ levelsRouter.get("/config", async (c2) => {
123530
+ const ctx = {
123531
+ user: c2.get("user"),
123532
+ params: {},
123533
+ url: new URL(c2.req.url),
123534
+ request: c2.req.raw
123535
+ };
123536
+ try {
123537
+ const configs = await getAllLevelConfigs(ctx);
123538
+ return c2.json(configs);
123539
+ } catch (error2) {
123540
+ if (error2 instanceof ApiError) {
123541
+ return c2.json({ error: error2.message }, error2.statusCode);
123542
+ }
123543
+ console.error("Error in getAllLevelConfigs:", error2);
123544
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
123545
+ return c2.json({ error: message2 }, 500);
123546
+ }
123547
+ });
123548
+ levelsRouter.get("/config/:level", async (c2) => {
123549
+ const ctx = {
123550
+ user: c2.get("user"),
123551
+ params: { level: c2.req.param("level") },
123552
+ url: new URL(c2.req.url),
123553
+ request: c2.req.raw
123554
+ };
123555
+ try {
123556
+ const config = await getLevelConfigByPath(ctx);
123557
+ return c2.json(config);
123558
+ } catch (error2) {
123559
+ if (error2 instanceof ApiError) {
123560
+ return c2.json({ error: error2.message }, error2.statusCode);
123561
+ }
123562
+ console.error("Error in getLevelConfigByPath:", error2);
123563
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
123564
+ return c2.json({ error: message2 }, 500);
123565
+ }
123566
+ });
123136
123567
  async function startServer(options) {
123137
123568
  const { port, verbose, project } = options;
123138
123569
  configureLogger(verbose ? "debug" : "error");
@@ -123158,6 +123589,7 @@ async function startServer(options) {
123158
123589
  app.route("/api/maps", mapsRouter);
123159
123590
  app.route("/api/shop-listings", shopListingsRouter);
123160
123591
  app.route("/api/dev", devRouter);
123592
+ app.route("/api/levels", levelsRouter);
123161
123593
  return serve({ fetch: app.fetch, port });
123162
123594
  }
123163
123595
  var version3 = package_default.version;
@@ -123225,10 +123657,10 @@ function printSandboxInfo(viteConfig, availablePort, projectInfo) {
123225
123657
  viteConfig.logger.info(` ${import_picocolors.default.green("➜")} ${import_picocolors.default.bold("Sandbox:")} ${import_picocolors.default.cyan(`http://localhost:${import_picocolors.default.bold(availablePort.toString())}/api`)}`);
123226
123658
  viteConfig.logger.info("");
123227
123659
  }
123228
- async function startSandbox(viteConfig, autoStart = true, verbose = false) {
123660
+ async function startSandbox(viteConfig, autoStart = true, verbose = false, customUrl) {
123229
123661
  if (!autoStart || viteConfig.command !== "serve") {
123230
123662
  return {
123231
- url: "http://localhost:4321/api",
123663
+ url: customUrl ?? "http://localhost:4321/api",
123232
123664
  project: null,
123233
123665
  cleanup: () => {}
123234
123666
  };
@@ -123400,7 +123832,7 @@ var shell_default = `<!doctype html>
123400
123832
  </div>
123401
123833
 
123402
123834
  <script type="module">
123403
- import { bus, BusEvents } from '@playcademy/sdk'
123835
+ import { messaging, MessageEvents } from '@playcademy/sdk'
123404
123836
 
123405
123837
  const status = document.getElementById('status')
123406
123838
  const loading = document.getElementById('loading')
@@ -123446,16 +123878,17 @@ var shell_default = `<!doctype html>
123446
123878
  'Game iframe loaded, sending PLAYCADEMY_INIT message',
123447
123879
  )
123448
123880
 
123449
- gameFrame.contentWindow.postMessage(
123881
+ messaging.send(
123882
+ MessageEvents.INIT,
123883
+ {
123884
+ baseUrl: '{{SANDBOX_URL}}',
123885
+ token: 'dev-token',
123886
+ gameId: '{{GAME_ID}}',
123887
+ },
123450
123888
  {
123451
- type: BusEvents.INIT,
123452
- payload: {
123453
- baseUrl: '{{SANDBOX_URL}}',
123454
- token: 'dev-token',
123455
- gameId: '{{GAME_ID}}',
123456
- },
123889
+ target: gameFrame.contentWindow,
123890
+ origin: '*',
123457
123891
  },
123458
- '*',
123459
123892
  )
123460
123893
  }
123461
123894
 
@@ -123474,7 +123907,8 @@ var shell_default = `<!doctype html>
123474
123907
  const { type, ...payload } = event.data || {}
123475
123908
  if (type && type.startsWith('PLAYCADEMY_')) {
123476
123909
  logIfDebug('Received message from game:', type, payload)
123477
- bus.emit(type, payload)
123910
+ // Bridge the message to the local context using CustomEvent
123911
+ messaging.send(type, payload)
123478
123912
  }
123479
123913
  }
123480
123914
  })
@@ -123499,6 +123933,11 @@ function devServerMiddleware(server, sandboxUrl, project) {
123499
123933
  res.end(generateLoaderHTML(sandboxUrl, gameId));
123500
123934
  return;
123501
123935
  }
123936
+ if (req.url === "/game" && req.method === "GET") {
123937
+ req.url = "/index.html";
123938
+ next();
123939
+ return;
123940
+ }
123502
123941
  next();
123503
123942
  });
123504
123943
  }
@@ -123602,7 +124041,7 @@ function playcademy(options = {}) {
123602
124041
  platform: exportOptions.platform ?? "web",
123603
124042
  autoZip: exportOptions.autoZip ?? false,
123604
124043
  sandboxUrl: sandboxOptions.url ?? "http://localhost:4321/api",
123605
- startSandbox: sandboxOptions.autoStart ?? true,
124044
+ startSandbox: sandboxOptions.url ? false : sandboxOptions.autoStart ?? true,
123606
124045
  verbose: sandboxOptions.verbose ?? false
123607
124046
  };
123608
124047
  return {
@@ -123615,7 +124054,7 @@ function playcademy(options = {}) {
123615
124054
  currentBuildOutputs = {};
123616
124055
  },
123617
124056
  async configureServer(server) {
123618
- const sandbox = await startSandbox(viteConfig, _options.startSandbox, _options.verbose);
124057
+ const sandbox = await startSandbox(viteConfig, _options.startSandbox, _options.verbose, _options.sandboxUrl);
123619
124058
  sandboxCleanup = sandbox.cleanup;
123620
124059
  if (sandbox.project) {
123621
124060
  devServerMiddleware(server, sandbox.url, sandbox.project);
@@ -5,5 +5,5 @@ interface SandboxManager {
5
5
  project: ProjectInfo | null;
6
6
  cleanup: () => void;
7
7
  }
8
- export declare function startSandbox(viteConfig: ResolvedConfig, autoStart?: boolean, verbose?: boolean): Promise<SandboxManager>;
8
+ export declare function startSandbox(viteConfig: ResolvedConfig, autoStart?: boolean, verbose?: boolean, customUrl?: string): Promise<SandboxManager>;
9
9
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@playcademy/vite-plugin",
3
3
  "type": "module",
4
- "version": "0.0.1-beta.7",
4
+ "version": "0.0.1-beta.9",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
7
7
  "exports": {