@playcademy/vite-plugin 0.0.1-beta.10 → 0.0.1-beta.11

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.
Files changed (2) hide show
  1. package/dist/index.js +520 -175
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -7009,7 +7009,7 @@ var require_errors = __commonJS((exports, module2) => {
7009
7009
  };
7010
7010
  });
7011
7011
 
7012
- // ../../node_modules/event-target-shim/dist/event-target-shim.js
7012
+ // ../../node_modules/abort-controller/node_modules/event-target-shim/dist/event-target-shim.js
7013
7013
  var require_event_target_shim = __commonJS((exports, module2) => {
7014
7014
  Object.defineProperty(exports, "__esModule", { value: true });
7015
7015
  var privateData = new WeakMap;
@@ -14862,7 +14862,7 @@ globstar while`, file, fr, pattern, pr3, swallowee);
14862
14862
  exports.minimatch.unescape = unescape_js_1.unescape;
14863
14863
  });
14864
14864
 
14865
- // ../../node_modules/archiver-utils/node_modules/glob/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js
14865
+ // ../../node_modules/lru-cache/dist/commonjs/index.js
14866
14866
  var require_commonjs2 = __commonJS((exports) => {
14867
14867
  Object.defineProperty(exports, "__esModule", { value: true });
14868
14868
  exports.LRUCache = undefined;
@@ -94251,7 +94251,8 @@ var PLAYCADEMY_CREDITS_ID = crypto.randomUUID();
94251
94251
  var SAMPLE_ITEMS = [
94252
94252
  {
94253
94253
  id: PLAYCADEMY_CREDITS_ID,
94254
- internalName: "PLAYCADEMY_CREDITS",
94254
+ slug: "PLAYCADEMY_CREDITS",
94255
+ gameId: null,
94255
94256
  displayName: "PLAYCADEMY credits",
94256
94257
  description: "The main currency used across PLAYCADEMY.",
94257
94258
  type: "currency",
@@ -94262,7 +94263,8 @@ var SAMPLE_ITEMS = [
94262
94263
  },
94263
94264
  {
94264
94265
  id: crypto.randomUUID(),
94265
- internalName: "FOUNDING_MEMBER_BADGE",
94266
+ slug: "FOUNDING_MEMBER_BADGE",
94267
+ gameId: null,
94266
94268
  displayName: "Founding Member Badge",
94267
94269
  description: "Reserved for founding core team of the PLAYCADEMY platform.",
94268
94270
  type: "badge",
@@ -94273,7 +94275,8 @@ var SAMPLE_ITEMS = [
94273
94275
  },
94274
94276
  {
94275
94277
  id: crypto.randomUUID(),
94276
- internalName: "EARLY_ADOPTER_BADGE",
94278
+ slug: "EARLY_ADOPTER_BADGE",
94279
+ gameId: null,
94277
94280
  displayName: "Early Adopter Badge",
94278
94281
  description: "Awarded to users who joined during the beta phase.",
94279
94282
  type: "badge",
@@ -94284,7 +94287,8 @@ var SAMPLE_ITEMS = [
94284
94287
  },
94285
94288
  {
94286
94289
  id: crypto.randomUUID(),
94287
- internalName: "FIRST_GAME_BADGE",
94290
+ slug: "FIRST_GAME_BADGE",
94291
+ gameId: null,
94288
94292
  displayName: "First Game Played",
94289
94293
  description: "Awarded for playing your first game in the Playcademy platform.",
94290
94294
  type: "badge",
@@ -94295,7 +94299,8 @@ var SAMPLE_ITEMS = [
94295
94299
  },
94296
94300
  {
94297
94301
  id: crypto.randomUUID(),
94298
- internalName: "COMMON_SWORD",
94302
+ slug: "COMMON_SWORD",
94303
+ gameId: null,
94299
94304
  displayName: "Common Sword",
94300
94305
  description: "A basic sword, good for beginners.",
94301
94306
  type: "unlock",
@@ -94304,7 +94309,8 @@ var SAMPLE_ITEMS = [
94304
94309
  },
94305
94310
  {
94306
94311
  id: crypto.randomUUID(),
94307
- internalName: "SMALL_HEALTH_POTION",
94312
+ slug: "SMALL_HEALTH_POTION",
94313
+ gameId: null,
94308
94314
  displayName: "Small Health Potion",
94309
94315
  description: "Restores a small amount of health.",
94310
94316
  type: "other",
@@ -94313,7 +94319,8 @@ var SAMPLE_ITEMS = [
94313
94319
  },
94314
94320
  {
94315
94321
  id: crypto.randomUUID(),
94316
- internalName: "SMALL_BACKPACK",
94322
+ slug: "SMALL_BACKPACK",
94323
+ gameId: null,
94317
94324
  displayName: "Small Backpack",
94318
94325
  description: "Increases your inventory capacity by 5 slots.",
94319
94326
  type: "upgrade",
@@ -118653,14 +118660,20 @@ var itemTypeEnum = pgEnum("item_type", [
118653
118660
  ]);
118654
118661
  var items = pgTable("items", {
118655
118662
  id: uuid("id").primaryKey().defaultRandom(),
118656
- internalName: text("internal_name").notNull().unique(),
118663
+ slug: text("slug").notNull(),
118664
+ gameId: uuid("game_id").references(() => games.id, {
118665
+ onDelete: "cascade"
118666
+ }),
118657
118667
  displayName: text("display_name").notNull(),
118658
118668
  description: text("description"),
118659
118669
  type: itemTypeEnum("type").notNull().default("other"),
118660
118670
  imageUrl: text("image_url"),
118661
118671
  metadata: jsonb("metadata").default({}),
118662
118672
  createdAt: timestamp("created_at").defaultNow().notNull()
118663
- });
118673
+ }, (table6) => [
118674
+ uniqueIndex("items_game_slug_idx").on(table6.gameId, table6.slug),
118675
+ uniqueIndex("items_global_slug_idx").on(table6.slug).where(sql`game_id IS NULL`)
118676
+ ]);
118664
118677
  var inventoryItems = pgTable("inventory_items", {
118665
118678
  id: uuid("id").primaryKey().defaultRandom(),
118666
118679
  userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
@@ -118693,9 +118706,13 @@ var shopListings = pgTable("shop_listings", {
118693
118706
  }, (table6) => [
118694
118707
  uniqueIndex("unique_item_currency_listing_idx").on(table6.itemId, table6.currencyId)
118695
118708
  ]);
118696
- var itemsRelations = relations(items, ({ many }) => ({
118709
+ var itemsRelations = relations(items, ({ many, one }) => ({
118697
118710
  shopListings: many(shopListings),
118698
- inventoryItems: many(inventoryItems)
118711
+ inventoryItems: many(inventoryItems),
118712
+ game: one(games, {
118713
+ fields: [items.gameId],
118714
+ references: [games.id]
118715
+ })
118699
118716
  }));
118700
118717
  var currenciesRelations = relations(currencies, ({ many }) => ({
118701
118718
  shopListings: many(shopListings)
@@ -118744,14 +118761,18 @@ var ItemMetadataSchema = exports_external.object({
118744
118761
  var InsertItemSchema = createInsertSchema(items, {
118745
118762
  imageUrl: exports_external.string().refine((val) => validateRelativePath2(val, "imageUrl")).optional().nullable(),
118746
118763
  type: exports_external.enum(itemTypeEnum.enumValues).default("other"),
118747
- metadata: ItemMetadataSchema.optional()
118764
+ metadata: ItemMetadataSchema.optional(),
118765
+ gameId: exports_external.string().uuid().optional().nullable()
118748
118766
  }).omit({ id: true });
118749
118767
  var SelectItemSchema = createSelectSchema(items);
118750
118768
  var UpdateItemSchema = InsertItemSchema.pick({
118769
+ slug: true,
118770
+ displayName: true,
118771
+ description: true,
118751
118772
  type: true,
118752
118773
  metadata: true,
118753
118774
  imageUrl: true
118754
- });
118775
+ }).partial();
118755
118776
  var InsertInventoryItemSchema = createInsertSchema(inventoryItems).omit({
118756
118777
  id: true,
118757
118778
  updatedAt: true
@@ -118978,7 +118999,7 @@ async function seedCurrentProjectGame(db, project) {
118978
118999
  }
118979
119000
  var package_default = {
118980
119001
  name: "@playcademy/sandbox",
118981
- version: "0.1.0-beta.6",
119002
+ version: "0.1.0-beta.7",
118982
119003
  description: "Local development server for Playcademy game development",
118983
119004
  type: "module",
118984
119005
  exports: {
@@ -119078,7 +119099,7 @@ async function getUserMe(ctx) {
119078
119099
  throw ApiError.internal("Internal server error", error2);
119079
119100
  }
119080
119101
  }
119081
- var ITEM_INTERNAL_NAMES = {
119102
+ var ITEM_SLUGS = {
119082
119103
  PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
119083
119104
  PLAYCADEMY_XP: "PLAYCADEMY_XP",
119084
119105
  FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
@@ -119089,14 +119110,15 @@ var ITEM_INTERNAL_NAMES = {
119089
119110
  SMALL_BACKPACK: "SMALL_BACKPACK"
119090
119111
  };
119091
119112
  var CURRENCIES = {
119092
- PRIMARY: ITEM_INTERNAL_NAMES.PLAYCADEMY_CREDITS,
119093
- XP: ITEM_INTERNAL_NAMES.PLAYCADEMY_XP
119113
+ PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
119114
+ XP: ITEM_SLUGS.PLAYCADEMY_XP
119094
119115
  };
119095
119116
  var BADGES = {
119096
- FOUNDING_MEMBER: ITEM_INTERNAL_NAMES.FOUNDING_MEMBER_BADGE,
119097
- EARLY_ADOPTER: ITEM_INTERNAL_NAMES.EARLY_ADOPTER_BADGE,
119098
- FIRST_GAME: ITEM_INTERNAL_NAMES.FIRST_GAME_BADGE
119117
+ FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
119118
+ EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
119119
+ FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
119099
119120
  };
119121
+ var INTERACTION_TYPE = Object.fromEntries(interactionTypeEnum.enumValues.map((value) => [value, value]));
119100
119122
  var levelConfigCache = null;
119101
119123
  async function getLevelConfig(db, level) {
119102
119124
  if (level < 1) {
@@ -119247,7 +119269,7 @@ async function addXP(ctx, amount) {
119247
119269
  creditsAwarded: creditsToAward
119248
119270
  });
119249
119271
  if (creditsToAward > 0) {
119250
- const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.internalName, CURRENCIES.PRIMARY)).limit(1);
119272
+ const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
119251
119273
  if (!creditsItem) {
119252
119274
  throw ApiError.internal(`${CURRENCIES.PRIMARY} item not found`);
119253
119275
  }
@@ -119443,15 +119465,18 @@ async function getUserInventory(ctx) {
119443
119465
  const db = getDatabase();
119444
119466
  const inventory2 = await db.select({
119445
119467
  id: inventoryItems.id,
119468
+ userId: inventoryItems.userId,
119446
119469
  quantity: inventoryItems.quantity,
119447
119470
  item: {
119448
119471
  id: items.id,
119449
- internalName: items.internalName,
119472
+ slug: items.slug,
119473
+ gameId: items.gameId,
119450
119474
  displayName: items.displayName,
119451
119475
  description: items.description,
119452
119476
  type: items.type,
119453
119477
  imageUrl: items.imageUrl,
119454
- metadata: items.metadata
119478
+ metadata: items.metadata,
119479
+ createdAt: items.createdAt
119455
119480
  },
119456
119481
  updatedAt: inventoryItems.updatedAt
119457
119482
  }).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
@@ -120997,14 +121022,13 @@ async function listGames(ctx) {
120997
121022
  if (!user) {
120998
121023
  throw ApiError.unauthorized("Must be logged in to list games");
120999
121024
  }
121000
- if (user.role !== "admin" && user.role !== "developer") {
121001
- throw ApiError.forbidden("Requires admin or developer privileges to list games");
121002
- }
121003
121025
  try {
121004
121026
  const db = getDatabase();
121005
121027
  let filter2 = undefined;
121006
121028
  if (user.role === "developer") {
121007
121029
  filter2 = eq(games.developerId, user.id);
121030
+ } else if (user.role === "player") {
121031
+ return [];
121008
121032
  }
121009
121033
  const games2 = await db.query.games.findMany({
121010
121034
  where: filter2,
@@ -121245,6 +121269,373 @@ async function upsertGameBySlug(ctx) {
121245
121269
  throw ApiError.internal("Internal server error", error2);
121246
121270
  }
121247
121271
  }
121272
+ async function validateGameOwnership(user, gameId) {
121273
+ if (user.role === "admin") {
121274
+ return;
121275
+ }
121276
+ try {
121277
+ const db = getDatabase();
121278
+ const gameOwnership = await db.query.games.findFirst({
121279
+ where: and(eq(games.id, gameId), eq(games.developerId, user.id)),
121280
+ columns: { id: true }
121281
+ });
121282
+ if (!gameOwnership) {
121283
+ const gameExists = await db.query.games.findFirst({
121284
+ where: eq(games.id, gameId),
121285
+ columns: { id: true }
121286
+ });
121287
+ if (!gameExists) {
121288
+ throw ApiError.notFound("Game not found");
121289
+ }
121290
+ throw ApiError.forbidden("You do not own this game");
121291
+ }
121292
+ } catch (error2) {
121293
+ if (error2 instanceof ApiError) {
121294
+ throw error2;
121295
+ }
121296
+ logger2.error(`Error checking game ownership for ${gameId}:`, error2);
121297
+ throw ApiError.internal("Internal server error", error2);
121298
+ }
121299
+ }
121300
+ async function listItems(ctx) {
121301
+ const user = ctx.user;
121302
+ if (!user) {
121303
+ throw ApiError.unauthorized("Must be logged in to view items");
121304
+ }
121305
+ try {
121306
+ const db = getDatabase();
121307
+ const url2 = new URL(ctx.request.url);
121308
+ const gameId = url2.searchParams.get("gameId");
121309
+ let allItems;
121310
+ if (gameId) {
121311
+ allItems = await db.query.items.findMany({
121312
+ where: eq(items.gameId, gameId)
121313
+ });
121314
+ } else {
121315
+ allItems = await db.query.items.findMany();
121316
+ }
121317
+ return allItems;
121318
+ } catch (error2) {
121319
+ if (error2 instanceof ApiError) {
121320
+ throw error2;
121321
+ }
121322
+ logger2.error("Error fetching items:", error2);
121323
+ throw ApiError.internal("Internal server error", error2);
121324
+ }
121325
+ }
121326
+ async function getItemById(ctx) {
121327
+ const user = ctx.user;
121328
+ const itemId = ctx.params.itemId;
121329
+ if (!user) {
121330
+ throw ApiError.unauthorized("Must be logged in to view item details");
121331
+ }
121332
+ if (!itemId) {
121333
+ throw ApiError.badRequest("Missing item ID");
121334
+ }
121335
+ try {
121336
+ const db = getDatabase();
121337
+ const item = await db.query.items.findFirst({
121338
+ where: eq(items.id, itemId)
121339
+ });
121340
+ if (!item) {
121341
+ throw ApiError.notFound("Item not found");
121342
+ }
121343
+ return item;
121344
+ } catch (error2) {
121345
+ if (error2 instanceof ApiError) {
121346
+ throw error2;
121347
+ }
121348
+ logger2.error(`Error fetching item ${itemId}:`, error2);
121349
+ throw ApiError.internal("Internal server error", error2);
121350
+ }
121351
+ }
121352
+ async function createItem(ctx) {
121353
+ const user = ctx.user;
121354
+ if (!user || user.role !== "admin") {
121355
+ throw ApiError.forbidden("Admin access required");
121356
+ }
121357
+ let inputData;
121358
+ try {
121359
+ const requestBody = await ctx.request.json();
121360
+ const validationResult = InsertItemSchema.safeParse(requestBody);
121361
+ if (!validationResult.success) {
121362
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
121363
+ }
121364
+ inputData = validationResult.data;
121365
+ } catch (error2) {
121366
+ if (error2 instanceof ApiError) {
121367
+ throw error2;
121368
+ }
121369
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
121370
+ throw ApiError.badRequest("Invalid JSON body");
121371
+ }
121372
+ try {
121373
+ const db = getDatabase();
121374
+ const [newItem] = await db.insert(items).values(inputData).returning();
121375
+ if (!newItem) {
121376
+ throw ApiError.internal("Failed to create item in database");
121377
+ }
121378
+ return newItem;
121379
+ } catch (error2) {
121380
+ if (error2 instanceof Error) {
121381
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
121382
+ const gameScope = inputData.gameId ? "for this game" : "as a platform item";
121383
+ throw ApiError.conflict(`An item with slug '${inputData.slug}' already exists ${gameScope}`);
121384
+ }
121385
+ }
121386
+ logger2.error("Error creating item:", error2);
121387
+ throw ApiError.internal("Internal server error", error2);
121388
+ }
121389
+ }
121390
+ async function updateItem(ctx) {
121391
+ const user = ctx.user;
121392
+ const itemId = ctx.params.itemId;
121393
+ if (!user || user.role !== "admin") {
121394
+ throw ApiError.forbidden("Admin access required");
121395
+ }
121396
+ if (!itemId) {
121397
+ throw ApiError.badRequest("Missing item ID");
121398
+ }
121399
+ let inputData;
121400
+ try {
121401
+ const requestBody = await ctx.request.json();
121402
+ const validationResult = UpdateItemSchema.safeParse(requestBody);
121403
+ if (!validationResult.success) {
121404
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
121405
+ }
121406
+ inputData = validationResult.data;
121407
+ } catch (error2) {
121408
+ if (error2 instanceof ApiError) {
121409
+ throw error2;
121410
+ }
121411
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
121412
+ throw ApiError.badRequest("Invalid JSON body");
121413
+ }
121414
+ if (Object.keys(inputData).length === 0) {
121415
+ throw ApiError.badRequest("No update data provided");
121416
+ }
121417
+ try {
121418
+ const db = getDatabase();
121419
+ const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
121420
+ if (!updatedItem) {
121421
+ throw ApiError.notFound("Item not found for update");
121422
+ }
121423
+ return updatedItem;
121424
+ } catch (error2) {
121425
+ if (error2 instanceof Error) {
121426
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
121427
+ throw ApiError.conflict("An item with this slug already exists within the same scope (platform or game)");
121428
+ }
121429
+ }
121430
+ logger2.error(`Error updating item ${itemId}:`, error2);
121431
+ throw ApiError.internal("Internal server error", error2);
121432
+ }
121433
+ }
121434
+ async function deleteItem(ctx) {
121435
+ const user = ctx.user;
121436
+ const itemId = ctx.params.itemId;
121437
+ if (!user || user.role !== "admin") {
121438
+ throw ApiError.forbidden("Admin access required");
121439
+ }
121440
+ if (!itemId) {
121441
+ throw ApiError.badRequest("Missing item ID");
121442
+ }
121443
+ try {
121444
+ const db = getDatabase();
121445
+ const result = await db.delete(items).where(eq(items.id, itemId)).returning({ id: items.id });
121446
+ if (result.length === 0) {
121447
+ throw ApiError.notFound("Item not found for deletion");
121448
+ }
121449
+ } catch (error2) {
121450
+ if (error2 instanceof ApiError) {
121451
+ throw error2;
121452
+ }
121453
+ logger2.error(`Error deleting item ${itemId}:`, error2);
121454
+ throw ApiError.internal("Internal server error", error2);
121455
+ }
121456
+ }
121457
+ async function resolveItem(ctx) {
121458
+ const user = ctx.user;
121459
+ const url2 = new URL(ctx.request.url);
121460
+ const slug = url2.searchParams.get("slug");
121461
+ const gameId = url2.searchParams.get("gameId");
121462
+ if (!user) {
121463
+ throw ApiError.unauthorized("Must be logged in to resolve items");
121464
+ }
121465
+ if (!slug) {
121466
+ throw ApiError.badRequest("Missing slug parameter");
121467
+ }
121468
+ try {
121469
+ const db = getDatabase();
121470
+ if (gameId) {
121471
+ const gameItem = await db.query.items.findFirst({
121472
+ where: and(eq(items.slug, slug), eq(items.gameId, gameId))
121473
+ });
121474
+ if (gameItem) {
121475
+ return gameItem;
121476
+ }
121477
+ }
121478
+ const platformItem = await db.query.items.findFirst({
121479
+ where: and(eq(items.slug, slug), isNull(items.gameId))
121480
+ });
121481
+ if (!platformItem) {
121482
+ throw ApiError.notFound(`Item with slug '${slug}' not found`);
121483
+ }
121484
+ return platformItem;
121485
+ } catch (error2) {
121486
+ if (error2 instanceof ApiError) {
121487
+ throw error2;
121488
+ }
121489
+ logger2.error(`Error resolving item slug ${slug}:`, error2);
121490
+ throw ApiError.internal("Internal server error", error2);
121491
+ }
121492
+ }
121493
+ async function listGameItems(ctx) {
121494
+ const user = ctx.user;
121495
+ const gameId = ctx.params.gameId;
121496
+ if (!user) {
121497
+ throw ApiError.unauthorized("Must be logged in to view items");
121498
+ }
121499
+ if (!gameId) {
121500
+ throw ApiError.badRequest("Missing game ID");
121501
+ }
121502
+ try {
121503
+ const db = getDatabase();
121504
+ const gameItems = await db.query.items.findMany({
121505
+ where: eq(items.gameId, gameId)
121506
+ });
121507
+ return gameItems;
121508
+ } catch (error2) {
121509
+ if (error2 instanceof ApiError) {
121510
+ throw error2;
121511
+ }
121512
+ logger2.error(`Error fetching items for game ${gameId}:`, error2);
121513
+ throw ApiError.internal("Internal server error", error2);
121514
+ }
121515
+ }
121516
+ async function createGameItem(ctx) {
121517
+ const user = ctx.user;
121518
+ const gameId = ctx.params.gameId;
121519
+ if (!user) {
121520
+ throw ApiError.unauthorized("Must be logged in to create items");
121521
+ }
121522
+ if (!gameId) {
121523
+ throw ApiError.badRequest("Missing game ID");
121524
+ }
121525
+ await validateGameOwnership(user, gameId);
121526
+ let inputData;
121527
+ try {
121528
+ const requestBody = await ctx.request.json();
121529
+ const bodyData = typeof requestBody === "object" && requestBody !== null ? requestBody : {};
121530
+ const validationResult = InsertItemSchema.safeParse({
121531
+ ...bodyData,
121532
+ gameId
121533
+ });
121534
+ if (!validationResult.success) {
121535
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
121536
+ }
121537
+ inputData = validationResult.data;
121538
+ } catch (error2) {
121539
+ if (error2 instanceof ApiError) {
121540
+ throw error2;
121541
+ }
121542
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
121543
+ throw ApiError.badRequest("Invalid JSON body");
121544
+ }
121545
+ try {
121546
+ const db = getDatabase();
121547
+ const [newItem] = await db.insert(items).values(inputData).returning();
121548
+ if (!newItem) {
121549
+ throw ApiError.internal("Failed to create item in database");
121550
+ }
121551
+ return newItem;
121552
+ } catch (error2) {
121553
+ if (error2 instanceof Error) {
121554
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
121555
+ throw ApiError.conflict(`An item with slug '${inputData.slug}' already exists for this game`);
121556
+ }
121557
+ }
121558
+ logger2.error("Error creating game item:", error2);
121559
+ throw ApiError.internal("Internal server error", error2);
121560
+ }
121561
+ }
121562
+ async function updateGameItem(ctx) {
121563
+ const user = ctx.user;
121564
+ const gameId = ctx.params.gameId;
121565
+ const itemId = ctx.params.itemId;
121566
+ if (!user) {
121567
+ throw ApiError.unauthorized("Must be logged in to update items");
121568
+ }
121569
+ if (!gameId || !itemId) {
121570
+ throw ApiError.badRequest("Missing game ID or item ID");
121571
+ }
121572
+ await validateGameOwnership(user, gameId);
121573
+ let inputData;
121574
+ try {
121575
+ const requestBody = await ctx.request.json();
121576
+ const validationResult = UpdateItemSchema.safeParse(requestBody);
121577
+ if (!validationResult.success) {
121578
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
121579
+ }
121580
+ inputData = validationResult.data;
121581
+ } catch (error2) {
121582
+ if (error2 instanceof ApiError) {
121583
+ throw error2;
121584
+ }
121585
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
121586
+ throw ApiError.badRequest("Invalid JSON body");
121587
+ }
121588
+ if (Object.keys(inputData).length === 0) {
121589
+ throw ApiError.badRequest("No update data provided");
121590
+ }
121591
+ try {
121592
+ const db = getDatabase();
121593
+ const existingItem = await db.query.items.findFirst({
121594
+ where: and(eq(items.id, itemId), eq(items.gameId, gameId))
121595
+ });
121596
+ if (!existingItem) {
121597
+ throw ApiError.notFound("Item not found for this game");
121598
+ }
121599
+ const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
121600
+ if (!updatedItem) {
121601
+ throw ApiError.notFound("Item not found for update");
121602
+ }
121603
+ return updatedItem;
121604
+ } catch (error2) {
121605
+ if (error2 instanceof Error) {
121606
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
121607
+ throw ApiError.conflict("An item with this slug already exists for this game");
121608
+ }
121609
+ }
121610
+ logger2.error(`Error updating game item ${itemId}:`, error2);
121611
+ throw ApiError.internal("Internal server error", error2);
121612
+ }
121613
+ }
121614
+ async function deleteGameItem(ctx) {
121615
+ const user = ctx.user;
121616
+ const gameId = ctx.params.gameId;
121617
+ const itemId = ctx.params.itemId;
121618
+ if (!user) {
121619
+ throw ApiError.unauthorized("Must be logged in to delete items");
121620
+ }
121621
+ if (!gameId || !itemId) {
121622
+ throw ApiError.badRequest("Missing game ID or item ID");
121623
+ }
121624
+ await validateGameOwnership(user, gameId);
121625
+ try {
121626
+ const db = getDatabase();
121627
+ const result = await db.delete(items).where(and(eq(items.id, itemId), eq(items.gameId, gameId))).returning({ id: items.id });
121628
+ if (result.length === 0) {
121629
+ throw ApiError.notFound("Item not found for this game");
121630
+ }
121631
+ } catch (error2) {
121632
+ if (error2 instanceof ApiError) {
121633
+ throw error2;
121634
+ }
121635
+ logger2.error(`Error deleting game item ${itemId}:`, error2);
121636
+ throw ApiError.internal("Internal server error", error2);
121637
+ }
121638
+ }
121248
121639
 
121249
121640
  class BigEndian {
121250
121641
  uint8(data2, offset) {
@@ -122318,6 +122709,88 @@ gamesRouter.post("/uploads/finalize", async (c2) => {
122318
122709
  return c2.json({ error: message2 }, 500);
122319
122710
  }
122320
122711
  });
122712
+ gamesRouter.get("/:gameId/items", async (c2) => {
122713
+ const gameId = c2.req.param("gameId");
122714
+ const ctx = {
122715
+ user: c2.get("user"),
122716
+ params: { gameId },
122717
+ url: new URL(c2.req.url),
122718
+ request: c2.req.raw
122719
+ };
122720
+ try {
122721
+ const result = await listGameItems(ctx);
122722
+ return c2.json(result);
122723
+ } catch (error2) {
122724
+ if (error2 instanceof ApiError) {
122725
+ return c2.json({ error: error2.message }, error2.statusCode);
122726
+ }
122727
+ console.error("Error in listGameItems:", error2);
122728
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
122729
+ return c2.json({ error: message2 }, 500);
122730
+ }
122731
+ });
122732
+ gamesRouter.post("/:gameId/items", async (c2) => {
122733
+ const gameId = c2.req.param("gameId");
122734
+ const ctx = {
122735
+ user: c2.get("user"),
122736
+ params: { gameId },
122737
+ url: new URL(c2.req.url),
122738
+ request: c2.req.raw
122739
+ };
122740
+ try {
122741
+ const result = await createGameItem(ctx);
122742
+ return c2.json(result, 201);
122743
+ } catch (error2) {
122744
+ if (error2 instanceof ApiError) {
122745
+ return c2.json({ error: error2.message }, error2.statusCode);
122746
+ }
122747
+ console.error("Error in createGameItem:", error2);
122748
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
122749
+ return c2.json({ error: message2 }, 500);
122750
+ }
122751
+ });
122752
+ gamesRouter.patch("/:gameId/items/:itemId", async (c2) => {
122753
+ const gameId = c2.req.param("gameId");
122754
+ const itemId = c2.req.param("itemId");
122755
+ const ctx = {
122756
+ user: c2.get("user"),
122757
+ params: { gameId, itemId },
122758
+ url: new URL(c2.req.url),
122759
+ request: c2.req.raw
122760
+ };
122761
+ try {
122762
+ const result = await updateGameItem(ctx);
122763
+ return c2.json(result);
122764
+ } catch (error2) {
122765
+ if (error2 instanceof ApiError) {
122766
+ return c2.json({ error: error2.message }, error2.statusCode);
122767
+ }
122768
+ console.error("Error in updateGameItem:", error2);
122769
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
122770
+ return c2.json({ error: message2 }, 500);
122771
+ }
122772
+ });
122773
+ gamesRouter.delete("/:gameId/items/:itemId", async (c2) => {
122774
+ const gameId = c2.req.param("gameId");
122775
+ const itemId = c2.req.param("itemId");
122776
+ const ctx = {
122777
+ user: c2.get("user"),
122778
+ params: { gameId, itemId },
122779
+ url: new URL(c2.req.url),
122780
+ request: c2.req.raw
122781
+ };
122782
+ try {
122783
+ await deleteGameItem(ctx);
122784
+ return c2.body(null, 204);
122785
+ } catch (error2) {
122786
+ if (error2 instanceof ApiError) {
122787
+ return c2.json({ error: error2.message }, error2.statusCode);
122788
+ }
122789
+ console.error("Error in deleteGameItem:", error2);
122790
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
122791
+ return c2.json({ error: message2 }, 500);
122792
+ }
122793
+ });
122321
122794
  var manifestRouter = new Hono2;
122322
122795
  manifestRouter.get("/", async (c2) => {
122323
122796
  const baseUrl = new URL(c2.req.url).origin;
@@ -122445,154 +122918,26 @@ shopRouter.get("/view", async (c2) => {
122445
122918
  return c2.json({ error: message2 }, 500);
122446
122919
  }
122447
122920
  });
122448
- async function listItems(ctx) {
122449
- const user = ctx.user;
122450
- if (!user) {
122451
- throw ApiError.unauthorized("Must be logged in to view items");
122452
- }
122453
- try {
122454
- const db = getDatabase();
122455
- const allItems = await db.query.items.findMany();
122456
- return allItems;
122457
- } catch (error2) {
122458
- if (error2 instanceof ApiError) {
122459
- throw error2;
122460
- }
122461
- logger2.error("Error fetching items:", error2);
122462
- throw ApiError.internal("Internal server error", error2);
122463
- }
122464
- }
122465
- async function getItemById(ctx) {
122466
- const user = ctx.user;
122467
- const itemId = ctx.params.itemId;
122468
- if (!user) {
122469
- throw ApiError.unauthorized("Must be logged in to view item details");
122470
- }
122471
- if (!itemId) {
122472
- throw ApiError.badRequest("Missing item ID");
122473
- }
122474
- try {
122475
- const db = getDatabase();
122476
- const item = await db.query.items.findFirst({
122477
- where: eq(items.id, itemId)
122478
- });
122479
- if (!item) {
122480
- throw ApiError.notFound("Item not found");
122481
- }
122482
- return item;
122483
- } catch (error2) {
122484
- if (error2 instanceof ApiError) {
122485
- throw error2;
122486
- }
122487
- logger2.error(`Error fetching item ${itemId}:`, error2);
122488
- throw ApiError.internal("Internal server error", error2);
122489
- }
122490
- }
122491
- async function createItem(ctx) {
122492
- const user = ctx.user;
122493
- if (!user || user.role !== "admin") {
122494
- throw ApiError.forbidden("Admin access required");
122495
- }
122496
- let inputData;
122497
- try {
122498
- const requestBody = await ctx.request.json();
122499
- const validationResult = InsertItemSchema.safeParse(requestBody);
122500
- if (!validationResult.success) {
122501
- throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
122502
- }
122503
- inputData = validationResult.data;
122504
- } catch (error2) {
122505
- if (error2 instanceof ApiError) {
122506
- throw error2;
122507
- }
122508
- logger2.error("Failed to parse request body or invalid JSON:", error2);
122509
- throw ApiError.badRequest("Invalid JSON body");
122510
- }
122511
- try {
122512
- const db = getDatabase();
122513
- const [newItem] = await db.insert(items).values(inputData).returning();
122514
- if (!newItem) {
122515
- throw ApiError.internal("Failed to create item in database");
122516
- }
122517
- return newItem;
122518
- } catch (error2) {
122519
- if (error2 instanceof Error) {
122520
- if (error2.message.includes("duplicate key value violates unique constraint")) {
122521
- throw ApiError.conflict("An item with this internal name already exists");
122522
- }
122523
- }
122524
- logger2.error("Error creating item:", error2);
122525
- throw ApiError.internal("Internal server error", error2);
122526
- }
122527
- }
122528
- async function updateItem(ctx) {
122529
- const user = ctx.user;
122530
- const itemId = ctx.params.itemId;
122531
- if (!user || user.role !== "admin") {
122532
- throw ApiError.forbidden("Admin access required");
122533
- }
122534
- if (!itemId) {
122535
- throw ApiError.badRequest("Missing item ID");
122536
- }
122537
- let inputData;
122538
- try {
122539
- const requestBody = await ctx.request.json();
122540
- const validationResult = UpdateItemSchema.safeParse(requestBody);
122541
- if (!validationResult.success) {
122542
- throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
122543
- }
122544
- inputData = validationResult.data;
122545
- } catch (error2) {
122546
- if (error2 instanceof ApiError) {
122547
- throw error2;
122548
- }
122549
- logger2.error("Failed to parse request body or invalid JSON:", error2);
122550
- throw ApiError.badRequest("Invalid JSON body");
122551
- }
122552
- if (Object.keys(inputData).length === 0) {
122553
- throw ApiError.badRequest("No update data provided");
122554
- }
122555
- try {
122556
- const db = getDatabase();
122557
- const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
122558
- if (!updatedItem) {
122559
- throw ApiError.notFound("Item not found for update");
122560
- }
122561
- return updatedItem;
122562
- } catch (error2) {
122563
- if (error2 instanceof Error) {
122564
- if (error2.message.includes("duplicate key value violates unique constraint")) {
122565
- throw ApiError.conflict("An item with this internal name already exists");
122566
- }
122567
- }
122568
- logger2.error(`Error updating item ${itemId}:`, error2);
122569
- throw ApiError.internal("Internal server error", error2);
122570
- }
122571
- }
122572
- async function deleteItem(ctx) {
122573
- const user = ctx.user;
122574
- const itemId = ctx.params.itemId;
122575
- if (!user || user.role !== "admin") {
122576
- throw ApiError.forbidden("Admin access required");
122577
- }
122578
- if (!itemId) {
122579
- throw ApiError.badRequest("Missing item ID");
122580
- }
122921
+ var itemsRouter = new Hono2;
122922
+ itemsRouter.get("/resolve", async (c2) => {
122923
+ const ctx = {
122924
+ user: c2.get("user"),
122925
+ params: {},
122926
+ url: new URL(c2.req.url),
122927
+ request: c2.req.raw
122928
+ };
122581
122929
  try {
122582
- const db = getDatabase();
122583
- const result = await db.delete(items).where(eq(items.id, itemId)).returning({ id: items.id });
122584
- if (result.length === 0) {
122585
- throw ApiError.notFound("Item not found for deletion");
122586
- }
122930
+ const result = await resolveItem(ctx);
122931
+ return c2.json(result);
122587
122932
  } catch (error2) {
122588
122933
  if (error2 instanceof ApiError) {
122589
- throw error2;
122934
+ return c2.json({ error: error2.message }, error2.statusCode);
122590
122935
  }
122591
- logger2.error(`Error deleting item ${itemId}:`, error2);
122592
- throw ApiError.internal("Internal server error", error2);
122936
+ console.error("Error in resolveItem:", error2);
122937
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
122938
+ return c2.json({ error: message2 }, 500);
122593
122939
  }
122594
- }
122595
- var itemsRouter = new Hono2;
122940
+ });
122596
122941
  itemsRouter.post("/", async (c2) => {
122597
122942
  const ctx = {
122598
122943
  user: c2.get("user"),
@@ -122764,8 +123109,8 @@ async function createCurrency(ctx) {
122764
123109
  } catch (error2) {
122765
123110
  if (error2 instanceof Error) {
122766
123111
  if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
122767
- if (error2.message.includes("currencies_internal_name_unique")) {
122768
- throw ApiError.conflict("A currency with this internal name already exists");
123112
+ if (error2.message.includes("currencies_slug_unique")) {
123113
+ throw ApiError.conflict("A currency with this slug already exists");
122769
123114
  }
122770
123115
  throw ApiError.conflict("A similar currency already exists");
122771
123116
  }
@@ -122811,8 +123156,8 @@ async function updateCurrency(ctx) {
122811
123156
  } catch (error2) {
122812
123157
  if (error2 instanceof Error) {
122813
123158
  if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
122814
- if (error2.message.includes("currencies_internal_name_unique")) {
122815
- throw ApiError.conflict("A currency with this internal name already exists");
123159
+ if (error2.message.includes("currencies_slug_unique")) {
123160
+ throw ApiError.conflict("A currency with this slug already exists");
122816
123161
  }
122817
123162
  throw ApiError.conflict("A similar currency already exists");
122818
123163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/vite-plugin",
3
- "version": "0.0.1-beta.10",
3
+ "version": "0.0.1-beta.11",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -23,7 +23,7 @@
23
23
  "picocolors": "^1.1.1"
24
24
  },
25
25
  "devDependencies": {
26
- "@playcademy/sandbox": "0.1.0-beta.7",
26
+ "@playcademy/sandbox": "0.1.0-beta.8",
27
27
  "@playcademy/types": "latest",
28
28
  "@types/archiver": "^6.0.3",
29
29
  "@types/bun": "latest",