@playcademy/sandbox 0.1.0-beta.7 → 0.1.0-beta.8

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 (3) hide show
  1. package/dist/cli.js +630 -285
  2. package/dist/server.js +631 -286
  3. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -50943,7 +50943,8 @@ var PLAYCADEMY_CREDITS_ID = crypto.randomUUID();
50943
50943
  var SAMPLE_ITEMS = [
50944
50944
  {
50945
50945
  id: PLAYCADEMY_CREDITS_ID,
50946
- internalName: "PLAYCADEMY_CREDITS",
50946
+ slug: "PLAYCADEMY_CREDITS",
50947
+ gameId: null,
50947
50948
  displayName: "PLAYCADEMY credits",
50948
50949
  description: "The main currency used across PLAYCADEMY.",
50949
50950
  type: "currency",
@@ -50954,7 +50955,8 @@ var SAMPLE_ITEMS = [
50954
50955
  },
50955
50956
  {
50956
50957
  id: crypto.randomUUID(),
50957
- internalName: "FOUNDING_MEMBER_BADGE",
50958
+ slug: "FOUNDING_MEMBER_BADGE",
50959
+ gameId: null,
50958
50960
  displayName: "Founding Member Badge",
50959
50961
  description: "Reserved for founding core team of the PLAYCADEMY platform.",
50960
50962
  type: "badge",
@@ -50965,7 +50967,8 @@ var SAMPLE_ITEMS = [
50965
50967
  },
50966
50968
  {
50967
50969
  id: crypto.randomUUID(),
50968
- internalName: "EARLY_ADOPTER_BADGE",
50970
+ slug: "EARLY_ADOPTER_BADGE",
50971
+ gameId: null,
50969
50972
  displayName: "Early Adopter Badge",
50970
50973
  description: "Awarded to users who joined during the beta phase.",
50971
50974
  type: "badge",
@@ -50976,7 +50979,8 @@ var SAMPLE_ITEMS = [
50976
50979
  },
50977
50980
  {
50978
50981
  id: crypto.randomUUID(),
50979
- internalName: "FIRST_GAME_BADGE",
50982
+ slug: "FIRST_GAME_BADGE",
50983
+ gameId: null,
50980
50984
  displayName: "First Game Played",
50981
50985
  description: "Awarded for playing your first game in the Playcademy platform.",
50982
50986
  type: "badge",
@@ -50987,7 +50991,8 @@ var SAMPLE_ITEMS = [
50987
50991
  },
50988
50992
  {
50989
50993
  id: crypto.randomUUID(),
50990
- internalName: "COMMON_SWORD",
50994
+ slug: "COMMON_SWORD",
50995
+ gameId: null,
50991
50996
  displayName: "Common Sword",
50992
50997
  description: "A basic sword, good for beginners.",
50993
50998
  type: "unlock",
@@ -50996,7 +51001,8 @@ var SAMPLE_ITEMS = [
50996
51001
  },
50997
51002
  {
50998
51003
  id: crypto.randomUUID(),
50999
- internalName: "SMALL_HEALTH_POTION",
51004
+ slug: "SMALL_HEALTH_POTION",
51005
+ gameId: null,
51000
51006
  displayName: "Small Health Potion",
51001
51007
  description: "Restores a small amount of health.",
51002
51008
  type: "other",
@@ -51005,7 +51011,8 @@ var SAMPLE_ITEMS = [
51005
51011
  },
51006
51012
  {
51007
51013
  id: crypto.randomUUID(),
51008
- internalName: "SMALL_BACKPACK",
51014
+ slug: "SMALL_BACKPACK",
51015
+ gameId: null,
51009
51016
  displayName: "Small Backpack",
51010
51017
  description: "Increases your inventory capacity by 5 slots.",
51011
51018
  type: "upgrade",
@@ -75478,14 +75485,20 @@ var itemTypeEnum = pgEnum("item_type", [
75478
75485
  ]);
75479
75486
  var items = pgTable("items", {
75480
75487
  id: uuid("id").primaryKey().defaultRandom(),
75481
- internalName: text("internal_name").notNull().unique(),
75488
+ slug: text("slug").notNull(),
75489
+ gameId: uuid("game_id").references(() => games.id, {
75490
+ onDelete: "cascade"
75491
+ }),
75482
75492
  displayName: text("display_name").notNull(),
75483
75493
  description: text("description"),
75484
75494
  type: itemTypeEnum("type").notNull().default("other"),
75485
75495
  imageUrl: text("image_url"),
75486
75496
  metadata: jsonb("metadata").default({}),
75487
75497
  createdAt: timestamp("created_at").defaultNow().notNull()
75488
- });
75498
+ }, (table) => [
75499
+ uniqueIndex("items_game_slug_idx").on(table.gameId, table.slug),
75500
+ uniqueIndex("items_global_slug_idx").on(table.slug).where(sql`game_id IS NULL`)
75501
+ ]);
75489
75502
  var inventoryItems = pgTable("inventory_items", {
75490
75503
  id: uuid("id").primaryKey().defaultRandom(),
75491
75504
  userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
@@ -75518,9 +75531,13 @@ var shopListings = pgTable("shop_listings", {
75518
75531
  }, (table) => [
75519
75532
  uniqueIndex("unique_item_currency_listing_idx").on(table.itemId, table.currencyId)
75520
75533
  ]);
75521
- var itemsRelations = relations(items, ({ many }) => ({
75534
+ var itemsRelations = relations(items, ({ many, one }) => ({
75522
75535
  shopListings: many(shopListings),
75523
- inventoryItems: many(inventoryItems)
75536
+ inventoryItems: many(inventoryItems),
75537
+ game: one(games, {
75538
+ fields: [items.gameId],
75539
+ references: [games.id]
75540
+ })
75524
75541
  }));
75525
75542
  var currenciesRelations = relations(currencies, ({ many }) => ({
75526
75543
  shopListings: many(shopListings)
@@ -75569,14 +75586,18 @@ var ItemMetadataSchema = exports_external.object({
75569
75586
  var InsertItemSchema = createInsertSchema(items, {
75570
75587
  imageUrl: exports_external.string().refine((val) => validateRelativePath2(val, "imageUrl")).optional().nullable(),
75571
75588
  type: exports_external.enum(itemTypeEnum.enumValues).default("other"),
75572
- metadata: ItemMetadataSchema.optional()
75589
+ metadata: ItemMetadataSchema.optional(),
75590
+ gameId: exports_external.string().uuid().optional().nullable()
75573
75591
  }).omit({ id: true });
75574
75592
  var SelectItemSchema = createSelectSchema(items);
75575
75593
  var UpdateItemSchema = InsertItemSchema.pick({
75594
+ slug: true,
75595
+ displayName: true,
75596
+ description: true,
75576
75597
  type: true,
75577
75598
  metadata: true,
75578
75599
  imageUrl: true
75579
- });
75600
+ }).partial();
75580
75601
  var InsertInventoryItemSchema = createInsertSchema(inventoryItems).omit({
75581
75602
  id: true,
75582
75603
  updatedAt: true
@@ -75812,7 +75833,7 @@ async function seedCurrentProjectGame(db, project) {
75812
75833
  // package.json
75813
75834
  var package_default = {
75814
75835
  name: "@playcademy/sandbox",
75815
- version: "0.1.0-beta.6",
75836
+ version: "0.1.0-beta.7",
75816
75837
  description: "Local development server for Playcademy game development",
75817
75838
  type: "module",
75818
75839
  exports: {
@@ -75917,7 +75938,7 @@ async function getUserMe(ctx) {
75917
75938
  }
75918
75939
 
75919
75940
  // ../data/src/constants.ts
75920
- var ITEM_INTERNAL_NAMES = {
75941
+ var ITEM_SLUGS = {
75921
75942
  PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
75922
75943
  PLAYCADEMY_XP: "PLAYCADEMY_XP",
75923
75944
  FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
@@ -75928,14 +75949,15 @@ var ITEM_INTERNAL_NAMES = {
75928
75949
  SMALL_BACKPACK: "SMALL_BACKPACK"
75929
75950
  };
75930
75951
  var CURRENCIES = {
75931
- PRIMARY: ITEM_INTERNAL_NAMES.PLAYCADEMY_CREDITS,
75932
- XP: ITEM_INTERNAL_NAMES.PLAYCADEMY_XP
75952
+ PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
75953
+ XP: ITEM_SLUGS.PLAYCADEMY_XP
75933
75954
  };
75934
75955
  var BADGES = {
75935
- FOUNDING_MEMBER: ITEM_INTERNAL_NAMES.FOUNDING_MEMBER_BADGE,
75936
- EARLY_ADOPTER: ITEM_INTERNAL_NAMES.EARLY_ADOPTER_BADGE,
75937
- FIRST_GAME: ITEM_INTERNAL_NAMES.FIRST_GAME_BADGE
75956
+ FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
75957
+ EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
75958
+ FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
75938
75959
  };
75960
+ var INTERACTION_TYPE = Object.fromEntries(interactionTypeEnum.enumValues.map((value) => [value, value]));
75939
75961
 
75940
75962
  // ../api-core/src/utils/levels.ts
75941
75963
  var levelConfigCache = null;
@@ -76092,7 +76114,7 @@ async function addXP(ctx, amount) {
76092
76114
  creditsAwarded: creditsToAward
76093
76115
  });
76094
76116
  if (creditsToAward > 0) {
76095
- const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.internalName, CURRENCIES.PRIMARY)).limit(1);
76117
+ const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
76096
76118
  if (!creditsItem) {
76097
76119
  throw ApiError.internal(`${CURRENCIES.PRIMARY} item not found`);
76098
76120
  }
@@ -76292,15 +76314,18 @@ async function getUserInventory(ctx) {
76292
76314
  const db = getDatabase();
76293
76315
  const inventory2 = await db.select({
76294
76316
  id: inventoryItems.id,
76317
+ userId: inventoryItems.userId,
76295
76318
  quantity: inventoryItems.quantity,
76296
76319
  item: {
76297
76320
  id: items.id,
76298
- internalName: items.internalName,
76321
+ slug: items.slug,
76322
+ gameId: items.gameId,
76299
76323
  displayName: items.displayName,
76300
76324
  description: items.description,
76301
76325
  type: items.type,
76302
76326
  imageUrl: items.imageUrl,
76303
- metadata: items.metadata
76327
+ metadata: items.metadata,
76328
+ createdAt: items.createdAt
76304
76329
  },
76305
76330
  updatedAt: inventoryItems.updatedAt
76306
76331
  }).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
@@ -77929,14 +77954,13 @@ async function listGames(ctx) {
77929
77954
  if (!user) {
77930
77955
  throw ApiError.unauthorized("Must be logged in to list games");
77931
77956
  }
77932
- if (user.role !== "admin" && user.role !== "developer") {
77933
- throw ApiError.forbidden("Requires admin or developer privileges to list games");
77934
- }
77935
77957
  try {
77936
77958
  const db = getDatabase();
77937
77959
  let filter2 = undefined;
77938
77960
  if (user.role === "developer") {
77939
77961
  filter2 = eq(games.developerId, user.id);
77962
+ } else if (user.role === "player") {
77963
+ return [];
77940
77964
  }
77941
77965
  const games2 = await db.query.games.findMany({
77942
77966
  where: filter2,
@@ -78177,147 +78201,516 @@ async function upsertGameBySlug(ctx) {
78177
78201
  throw ApiError.internal("Internal server error", error2);
78178
78202
  }
78179
78203
  }
78180
- // ../../node_modules/@oslojs/binary/dist/uint.js
78181
- class BigEndian {
78182
- uint8(data2, offset) {
78183
- if (data2.byteLength < offset + 1) {
78184
- throw new TypeError("Insufficient bytes");
78185
- }
78186
- return data2[offset];
78187
- }
78188
- uint16(data2, offset) {
78189
- if (data2.byteLength < offset + 2) {
78190
- throw new TypeError("Insufficient bytes");
78191
- }
78192
- return data2[offset] << 8 | data2[offset + 1];
78204
+
78205
+ // ../api-core/src/items/index.ts
78206
+ async function validateGameOwnership(user, gameId) {
78207
+ if (user.role === "admin") {
78208
+ return;
78193
78209
  }
78194
- uint32(data2, offset) {
78195
- if (data2.byteLength < offset + 4) {
78196
- throw new TypeError("Insufficient bytes");
78210
+ try {
78211
+ const db = getDatabase();
78212
+ const gameOwnership = await db.query.games.findFirst({
78213
+ where: and(eq(games.id, gameId), eq(games.developerId, user.id)),
78214
+ columns: { id: true }
78215
+ });
78216
+ if (!gameOwnership) {
78217
+ const gameExists = await db.query.games.findFirst({
78218
+ where: eq(games.id, gameId),
78219
+ columns: { id: true }
78220
+ });
78221
+ if (!gameExists) {
78222
+ throw ApiError.notFound("Game not found");
78223
+ }
78224
+ throw ApiError.forbidden("You do not own this game");
78197
78225
  }
78198
- let result = 0;
78199
- for (let i3 = 0;i3 < 4; i3++) {
78200
- result |= data2[offset + i3] << 24 - i3 * 8;
78226
+ } catch (error2) {
78227
+ if (error2 instanceof ApiError) {
78228
+ throw error2;
78201
78229
  }
78202
- return result;
78230
+ logger2.error(`Error checking game ownership for ${gameId}:`, error2);
78231
+ throw ApiError.internal("Internal server error", error2);
78203
78232
  }
78204
- uint64(data2, offset) {
78205
- if (data2.byteLength < offset + 8) {
78206
- throw new TypeError("Insufficient bytes");
78207
- }
78208
- let result = 0n;
78209
- for (let i3 = 0;i3 < 8; i3++) {
78210
- result |= BigInt(data2[offset + i3]) << BigInt(56 - i3 * 8);
78211
- }
78212
- return result;
78233
+ }
78234
+ async function listItems(ctx) {
78235
+ const user = ctx.user;
78236
+ if (!user) {
78237
+ throw ApiError.unauthorized("Must be logged in to view items");
78213
78238
  }
78214
- putUint8(target, value, offset) {
78215
- if (target.length < offset + 1) {
78216
- throw new TypeError("Not enough space");
78239
+ try {
78240
+ const db = getDatabase();
78241
+ const url2 = new URL(ctx.request.url);
78242
+ const gameId = url2.searchParams.get("gameId");
78243
+ let allItems;
78244
+ if (gameId) {
78245
+ allItems = await db.query.items.findMany({
78246
+ where: eq(items.gameId, gameId)
78247
+ });
78248
+ } else {
78249
+ allItems = await db.query.items.findMany();
78217
78250
  }
78218
- if (value < 0 || value > 255) {
78219
- throw new TypeError("Invalid uint8 value");
78251
+ return allItems;
78252
+ } catch (error2) {
78253
+ if (error2 instanceof ApiError) {
78254
+ throw error2;
78220
78255
  }
78221
- target[offset] = value;
78256
+ logger2.error("Error fetching items:", error2);
78257
+ throw ApiError.internal("Internal server error", error2);
78222
78258
  }
78223
- putUint16(target, value, offset) {
78224
- if (target.length < offset + 2) {
78225
- throw new TypeError("Not enough space");
78259
+ }
78260
+ async function getItemById(ctx) {
78261
+ const user = ctx.user;
78262
+ const itemId = ctx.params.itemId;
78263
+ if (!user) {
78264
+ throw ApiError.unauthorized("Must be logged in to view item details");
78265
+ }
78266
+ if (!itemId) {
78267
+ throw ApiError.badRequest("Missing item ID");
78268
+ }
78269
+ try {
78270
+ const db = getDatabase();
78271
+ const item = await db.query.items.findFirst({
78272
+ where: eq(items.id, itemId)
78273
+ });
78274
+ if (!item) {
78275
+ throw ApiError.notFound("Item not found");
78226
78276
  }
78227
- if (value < 0 || value > 65535) {
78228
- throw new TypeError("Invalid uint16 value");
78277
+ return item;
78278
+ } catch (error2) {
78279
+ if (error2 instanceof ApiError) {
78280
+ throw error2;
78229
78281
  }
78230
- target[offset] = value >> 8;
78231
- target[offset + 1] = value & 255;
78282
+ logger2.error(`Error fetching item ${itemId}:`, error2);
78283
+ throw ApiError.internal("Internal server error", error2);
78232
78284
  }
78233
- putUint32(target, value, offset) {
78234
- if (target.length < offset + 4) {
78235
- throw new TypeError("Not enough space");
78236
- }
78237
- if (value < 0 || value > 4294967295) {
78238
- throw new TypeError("Invalid uint32 value");
78285
+ }
78286
+ async function createItem(ctx) {
78287
+ const user = ctx.user;
78288
+ if (!user || user.role !== "admin") {
78289
+ throw ApiError.forbidden("Admin access required");
78290
+ }
78291
+ let inputData;
78292
+ try {
78293
+ const requestBody = await ctx.request.json();
78294
+ const validationResult = InsertItemSchema.safeParse(requestBody);
78295
+ if (!validationResult.success) {
78296
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
78239
78297
  }
78240
- for (let i3 = 0;i3 < 4; i3++) {
78241
- target[offset + i3] = value >> (3 - i3) * 8 & 255;
78298
+ inputData = validationResult.data;
78299
+ } catch (error2) {
78300
+ if (error2 instanceof ApiError) {
78301
+ throw error2;
78242
78302
  }
78303
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
78304
+ throw ApiError.badRequest("Invalid JSON body");
78243
78305
  }
78244
- putUint64(target, value, offset) {
78245
- if (target.length < offset + 8) {
78246
- throw new TypeError("Not enough space");
78247
- }
78248
- if (value < 0 || value > 18446744073709551615n) {
78249
- throw new TypeError("Invalid uint64 value");
78306
+ try {
78307
+ const db = getDatabase();
78308
+ const [newItem] = await db.insert(items).values(inputData).returning();
78309
+ if (!newItem) {
78310
+ throw ApiError.internal("Failed to create item in database");
78250
78311
  }
78251
- for (let i3 = 0;i3 < 8; i3++) {
78252
- target[offset + i3] = Number(value >> BigInt((7 - i3) * 8) & 0xffn);
78312
+ return newItem;
78313
+ } catch (error2) {
78314
+ if (error2 instanceof Error) {
78315
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
78316
+ const gameScope = inputData.gameId ? "for this game" : "as a platform item";
78317
+ throw ApiError.conflict(`An item with slug '${inputData.slug}' already exists ${gameScope}`);
78318
+ }
78253
78319
  }
78320
+ logger2.error("Error creating item:", error2);
78321
+ throw ApiError.internal("Internal server error", error2);
78254
78322
  }
78255
78323
  }
78256
-
78257
- class LittleEndian {
78258
- uint8(data2, offset) {
78259
- if (data2.byteLength < offset + 1) {
78260
- throw new TypeError("Insufficient bytes");
78261
- }
78262
- return data2[offset];
78324
+ async function updateItem(ctx) {
78325
+ const user = ctx.user;
78326
+ const itemId = ctx.params.itemId;
78327
+ if (!user || user.role !== "admin") {
78328
+ throw ApiError.forbidden("Admin access required");
78263
78329
  }
78264
- uint16(data2, offset) {
78265
- if (data2.byteLength < offset + 2) {
78266
- throw new TypeError("Insufficient bytes");
78267
- }
78268
- return data2[offset] | data2[offset + 1] << 8;
78330
+ if (!itemId) {
78331
+ throw ApiError.badRequest("Missing item ID");
78269
78332
  }
78270
- uint32(data2, offset) {
78271
- if (data2.byteLength < offset + 4) {
78272
- throw new TypeError("Insufficient bytes");
78333
+ let inputData;
78334
+ try {
78335
+ const requestBody = await ctx.request.json();
78336
+ const validationResult = UpdateItemSchema.safeParse(requestBody);
78337
+ if (!validationResult.success) {
78338
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
78273
78339
  }
78274
- let result = 0;
78275
- for (let i3 = 0;i3 < 4; i3++) {
78276
- result |= data2[offset + i3] << i3 * 8;
78340
+ inputData = validationResult.data;
78341
+ } catch (error2) {
78342
+ if (error2 instanceof ApiError) {
78343
+ throw error2;
78277
78344
  }
78278
- return result;
78345
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
78346
+ throw ApiError.badRequest("Invalid JSON body");
78279
78347
  }
78280
- uint64(data2, offset) {
78281
- if (data2.byteLength < offset + 8) {
78282
- throw new TypeError("Insufficient bytes");
78283
- }
78284
- let result = 0n;
78285
- for (let i3 = 0;i3 < 8; i3++) {
78286
- result |= BigInt(data2[offset + i3]) << BigInt(i3 * 8);
78287
- }
78288
- return result;
78348
+ if (Object.keys(inputData).length === 0) {
78349
+ throw ApiError.badRequest("No update data provided");
78289
78350
  }
78290
- putUint8(target, value, offset) {
78291
- if (target.length < 1 + offset) {
78292
- throw new TypeError("Insufficient space");
78351
+ try {
78352
+ const db = getDatabase();
78353
+ const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
78354
+ if (!updatedItem) {
78355
+ throw ApiError.notFound("Item not found for update");
78293
78356
  }
78294
- if (value < 0 || value > 255) {
78295
- throw new TypeError("Invalid uint8 value");
78357
+ return updatedItem;
78358
+ } catch (error2) {
78359
+ if (error2 instanceof Error) {
78360
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
78361
+ throw ApiError.conflict("An item with this slug already exists within the same scope (platform or game)");
78362
+ }
78296
78363
  }
78297
- target[offset] = value;
78364
+ logger2.error(`Error updating item ${itemId}:`, error2);
78365
+ throw ApiError.internal("Internal server error", error2);
78298
78366
  }
78299
- putUint16(target, value, offset) {
78300
- if (target.length < 2 + offset) {
78301
- throw new TypeError("Insufficient space");
78302
- }
78303
- if (value < 0 || value > 65535) {
78304
- throw new TypeError("Invalid uint16 value");
78305
- }
78306
- target[offset + 1] = value >> 8;
78307
- target[offset] = value & 255;
78367
+ }
78368
+ async function deleteItem(ctx) {
78369
+ const user = ctx.user;
78370
+ const itemId = ctx.params.itemId;
78371
+ if (!user || user.role !== "admin") {
78372
+ throw ApiError.forbidden("Admin access required");
78308
78373
  }
78309
- putUint32(target, value, offset) {
78310
- if (target.length < 4 + offset) {
78311
- throw new TypeError("Insufficient space");
78312
- }
78313
- if (value < 0 || value > 4294967295) {
78314
- throw new TypeError("Invalid uint32 value");
78374
+ if (!itemId) {
78375
+ throw ApiError.badRequest("Missing item ID");
78376
+ }
78377
+ try {
78378
+ const db = getDatabase();
78379
+ const result = await db.delete(items).where(eq(items.id, itemId)).returning({ id: items.id });
78380
+ if (result.length === 0) {
78381
+ throw ApiError.notFound("Item not found for deletion");
78315
78382
  }
78316
- for (let i3 = 0;i3 < 4; i3++) {
78317
- target[offset + i3] = value >> i3 * 8 & 255;
78383
+ } catch (error2) {
78384
+ if (error2 instanceof ApiError) {
78385
+ throw error2;
78318
78386
  }
78387
+ logger2.error(`Error deleting item ${itemId}:`, error2);
78388
+ throw ApiError.internal("Internal server error", error2);
78319
78389
  }
78320
- putUint64(target, value, offset) {
78390
+ }
78391
+ async function resolveItem(ctx) {
78392
+ const user = ctx.user;
78393
+ const url2 = new URL(ctx.request.url);
78394
+ const slug = url2.searchParams.get("slug");
78395
+ const gameId = url2.searchParams.get("gameId");
78396
+ if (!user) {
78397
+ throw ApiError.unauthorized("Must be logged in to resolve items");
78398
+ }
78399
+ if (!slug) {
78400
+ throw ApiError.badRequest("Missing slug parameter");
78401
+ }
78402
+ try {
78403
+ const db = getDatabase();
78404
+ if (gameId) {
78405
+ const gameItem = await db.query.items.findFirst({
78406
+ where: and(eq(items.slug, slug), eq(items.gameId, gameId))
78407
+ });
78408
+ if (gameItem) {
78409
+ return gameItem;
78410
+ }
78411
+ }
78412
+ const platformItem = await db.query.items.findFirst({
78413
+ where: and(eq(items.slug, slug), isNull(items.gameId))
78414
+ });
78415
+ if (!platformItem) {
78416
+ throw ApiError.notFound(`Item with slug '${slug}' not found`);
78417
+ }
78418
+ return platformItem;
78419
+ } catch (error2) {
78420
+ if (error2 instanceof ApiError) {
78421
+ throw error2;
78422
+ }
78423
+ logger2.error(`Error resolving item slug ${slug}:`, error2);
78424
+ throw ApiError.internal("Internal server error", error2);
78425
+ }
78426
+ }
78427
+ async function listGameItems(ctx) {
78428
+ const user = ctx.user;
78429
+ const gameId = ctx.params.gameId;
78430
+ if (!user) {
78431
+ throw ApiError.unauthorized("Must be logged in to view items");
78432
+ }
78433
+ if (!gameId) {
78434
+ throw ApiError.badRequest("Missing game ID");
78435
+ }
78436
+ try {
78437
+ const db = getDatabase();
78438
+ const gameItems = await db.query.items.findMany({
78439
+ where: eq(items.gameId, gameId)
78440
+ });
78441
+ return gameItems;
78442
+ } catch (error2) {
78443
+ if (error2 instanceof ApiError) {
78444
+ throw error2;
78445
+ }
78446
+ logger2.error(`Error fetching items for game ${gameId}:`, error2);
78447
+ throw ApiError.internal("Internal server error", error2);
78448
+ }
78449
+ }
78450
+ async function createGameItem(ctx) {
78451
+ const user = ctx.user;
78452
+ const gameId = ctx.params.gameId;
78453
+ if (!user) {
78454
+ throw ApiError.unauthorized("Must be logged in to create items");
78455
+ }
78456
+ if (!gameId) {
78457
+ throw ApiError.badRequest("Missing game ID");
78458
+ }
78459
+ await validateGameOwnership(user, gameId);
78460
+ let inputData;
78461
+ try {
78462
+ const requestBody = await ctx.request.json();
78463
+ const bodyData = typeof requestBody === "object" && requestBody !== null ? requestBody : {};
78464
+ const validationResult = InsertItemSchema.safeParse({
78465
+ ...bodyData,
78466
+ gameId
78467
+ });
78468
+ if (!validationResult.success) {
78469
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
78470
+ }
78471
+ inputData = validationResult.data;
78472
+ } catch (error2) {
78473
+ if (error2 instanceof ApiError) {
78474
+ throw error2;
78475
+ }
78476
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
78477
+ throw ApiError.badRequest("Invalid JSON body");
78478
+ }
78479
+ try {
78480
+ const db = getDatabase();
78481
+ const [newItem] = await db.insert(items).values(inputData).returning();
78482
+ if (!newItem) {
78483
+ throw ApiError.internal("Failed to create item in database");
78484
+ }
78485
+ return newItem;
78486
+ } catch (error2) {
78487
+ if (error2 instanceof Error) {
78488
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
78489
+ throw ApiError.conflict(`An item with slug '${inputData.slug}' already exists for this game`);
78490
+ }
78491
+ }
78492
+ logger2.error("Error creating game item:", error2);
78493
+ throw ApiError.internal("Internal server error", error2);
78494
+ }
78495
+ }
78496
+ async function updateGameItem(ctx) {
78497
+ const user = ctx.user;
78498
+ const gameId = ctx.params.gameId;
78499
+ const itemId = ctx.params.itemId;
78500
+ if (!user) {
78501
+ throw ApiError.unauthorized("Must be logged in to update items");
78502
+ }
78503
+ if (!gameId || !itemId) {
78504
+ throw ApiError.badRequest("Missing game ID or item ID");
78505
+ }
78506
+ await validateGameOwnership(user, gameId);
78507
+ let inputData;
78508
+ try {
78509
+ const requestBody = await ctx.request.json();
78510
+ const validationResult = UpdateItemSchema.safeParse(requestBody);
78511
+ if (!validationResult.success) {
78512
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
78513
+ }
78514
+ inputData = validationResult.data;
78515
+ } catch (error2) {
78516
+ if (error2 instanceof ApiError) {
78517
+ throw error2;
78518
+ }
78519
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
78520
+ throw ApiError.badRequest("Invalid JSON body");
78521
+ }
78522
+ if (Object.keys(inputData).length === 0) {
78523
+ throw ApiError.badRequest("No update data provided");
78524
+ }
78525
+ try {
78526
+ const db = getDatabase();
78527
+ const existingItem = await db.query.items.findFirst({
78528
+ where: and(eq(items.id, itemId), eq(items.gameId, gameId))
78529
+ });
78530
+ if (!existingItem) {
78531
+ throw ApiError.notFound("Item not found for this game");
78532
+ }
78533
+ const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
78534
+ if (!updatedItem) {
78535
+ throw ApiError.notFound("Item not found for update");
78536
+ }
78537
+ return updatedItem;
78538
+ } catch (error2) {
78539
+ if (error2 instanceof Error) {
78540
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
78541
+ throw ApiError.conflict("An item with this slug already exists for this game");
78542
+ }
78543
+ }
78544
+ logger2.error(`Error updating game item ${itemId}:`, error2);
78545
+ throw ApiError.internal("Internal server error", error2);
78546
+ }
78547
+ }
78548
+ async function deleteGameItem(ctx) {
78549
+ const user = ctx.user;
78550
+ const gameId = ctx.params.gameId;
78551
+ const itemId = ctx.params.itemId;
78552
+ if (!user) {
78553
+ throw ApiError.unauthorized("Must be logged in to delete items");
78554
+ }
78555
+ if (!gameId || !itemId) {
78556
+ throw ApiError.badRequest("Missing game ID or item ID");
78557
+ }
78558
+ await validateGameOwnership(user, gameId);
78559
+ try {
78560
+ const db = getDatabase();
78561
+ const result = await db.delete(items).where(and(eq(items.id, itemId), eq(items.gameId, gameId))).returning({ id: items.id });
78562
+ if (result.length === 0) {
78563
+ throw ApiError.notFound("Item not found for this game");
78564
+ }
78565
+ } catch (error2) {
78566
+ if (error2 instanceof ApiError) {
78567
+ throw error2;
78568
+ }
78569
+ logger2.error(`Error deleting game item ${itemId}:`, error2);
78570
+ throw ApiError.internal("Internal server error", error2);
78571
+ }
78572
+ }
78573
+ // ../../node_modules/@oslojs/binary/dist/uint.js
78574
+ class BigEndian {
78575
+ uint8(data2, offset) {
78576
+ if (data2.byteLength < offset + 1) {
78577
+ throw new TypeError("Insufficient bytes");
78578
+ }
78579
+ return data2[offset];
78580
+ }
78581
+ uint16(data2, offset) {
78582
+ if (data2.byteLength < offset + 2) {
78583
+ throw new TypeError("Insufficient bytes");
78584
+ }
78585
+ return data2[offset] << 8 | data2[offset + 1];
78586
+ }
78587
+ uint32(data2, offset) {
78588
+ if (data2.byteLength < offset + 4) {
78589
+ throw new TypeError("Insufficient bytes");
78590
+ }
78591
+ let result = 0;
78592
+ for (let i3 = 0;i3 < 4; i3++) {
78593
+ result |= data2[offset + i3] << 24 - i3 * 8;
78594
+ }
78595
+ return result;
78596
+ }
78597
+ uint64(data2, offset) {
78598
+ if (data2.byteLength < offset + 8) {
78599
+ throw new TypeError("Insufficient bytes");
78600
+ }
78601
+ let result = 0n;
78602
+ for (let i3 = 0;i3 < 8; i3++) {
78603
+ result |= BigInt(data2[offset + i3]) << BigInt(56 - i3 * 8);
78604
+ }
78605
+ return result;
78606
+ }
78607
+ putUint8(target, value, offset) {
78608
+ if (target.length < offset + 1) {
78609
+ throw new TypeError("Not enough space");
78610
+ }
78611
+ if (value < 0 || value > 255) {
78612
+ throw new TypeError("Invalid uint8 value");
78613
+ }
78614
+ target[offset] = value;
78615
+ }
78616
+ putUint16(target, value, offset) {
78617
+ if (target.length < offset + 2) {
78618
+ throw new TypeError("Not enough space");
78619
+ }
78620
+ if (value < 0 || value > 65535) {
78621
+ throw new TypeError("Invalid uint16 value");
78622
+ }
78623
+ target[offset] = value >> 8;
78624
+ target[offset + 1] = value & 255;
78625
+ }
78626
+ putUint32(target, value, offset) {
78627
+ if (target.length < offset + 4) {
78628
+ throw new TypeError("Not enough space");
78629
+ }
78630
+ if (value < 0 || value > 4294967295) {
78631
+ throw new TypeError("Invalid uint32 value");
78632
+ }
78633
+ for (let i3 = 0;i3 < 4; i3++) {
78634
+ target[offset + i3] = value >> (3 - i3) * 8 & 255;
78635
+ }
78636
+ }
78637
+ putUint64(target, value, offset) {
78638
+ if (target.length < offset + 8) {
78639
+ throw new TypeError("Not enough space");
78640
+ }
78641
+ if (value < 0 || value > 18446744073709551615n) {
78642
+ throw new TypeError("Invalid uint64 value");
78643
+ }
78644
+ for (let i3 = 0;i3 < 8; i3++) {
78645
+ target[offset + i3] = Number(value >> BigInt((7 - i3) * 8) & 0xffn);
78646
+ }
78647
+ }
78648
+ }
78649
+
78650
+ class LittleEndian {
78651
+ uint8(data2, offset) {
78652
+ if (data2.byteLength < offset + 1) {
78653
+ throw new TypeError("Insufficient bytes");
78654
+ }
78655
+ return data2[offset];
78656
+ }
78657
+ uint16(data2, offset) {
78658
+ if (data2.byteLength < offset + 2) {
78659
+ throw new TypeError("Insufficient bytes");
78660
+ }
78661
+ return data2[offset] | data2[offset + 1] << 8;
78662
+ }
78663
+ uint32(data2, offset) {
78664
+ if (data2.byteLength < offset + 4) {
78665
+ throw new TypeError("Insufficient bytes");
78666
+ }
78667
+ let result = 0;
78668
+ for (let i3 = 0;i3 < 4; i3++) {
78669
+ result |= data2[offset + i3] << i3 * 8;
78670
+ }
78671
+ return result;
78672
+ }
78673
+ uint64(data2, offset) {
78674
+ if (data2.byteLength < offset + 8) {
78675
+ throw new TypeError("Insufficient bytes");
78676
+ }
78677
+ let result = 0n;
78678
+ for (let i3 = 0;i3 < 8; i3++) {
78679
+ result |= BigInt(data2[offset + i3]) << BigInt(i3 * 8);
78680
+ }
78681
+ return result;
78682
+ }
78683
+ putUint8(target, value, offset) {
78684
+ if (target.length < 1 + offset) {
78685
+ throw new TypeError("Insufficient space");
78686
+ }
78687
+ if (value < 0 || value > 255) {
78688
+ throw new TypeError("Invalid uint8 value");
78689
+ }
78690
+ target[offset] = value;
78691
+ }
78692
+ putUint16(target, value, offset) {
78693
+ if (target.length < 2 + offset) {
78694
+ throw new TypeError("Insufficient space");
78695
+ }
78696
+ if (value < 0 || value > 65535) {
78697
+ throw new TypeError("Invalid uint16 value");
78698
+ }
78699
+ target[offset + 1] = value >> 8;
78700
+ target[offset] = value & 255;
78701
+ }
78702
+ putUint32(target, value, offset) {
78703
+ if (target.length < 4 + offset) {
78704
+ throw new TypeError("Insufficient space");
78705
+ }
78706
+ if (value < 0 || value > 4294967295) {
78707
+ throw new TypeError("Invalid uint32 value");
78708
+ }
78709
+ for (let i3 = 0;i3 < 4; i3++) {
78710
+ target[offset + i3] = value >> i3 * 8 & 255;
78711
+ }
78712
+ }
78713
+ putUint64(target, value, offset) {
78321
78714
  if (target.length < 8 + offset) {
78322
78715
  throw new TypeError("Insufficient space");
78323
78716
  }
@@ -79256,6 +79649,88 @@ gamesRouter.post("/uploads/finalize", async (c2) => {
79256
79649
  return c2.json({ error: message2 }, 500);
79257
79650
  }
79258
79651
  });
79652
+ gamesRouter.get("/:gameId/items", async (c2) => {
79653
+ const gameId = c2.req.param("gameId");
79654
+ const ctx = {
79655
+ user: c2.get("user"),
79656
+ params: { gameId },
79657
+ url: new URL(c2.req.url),
79658
+ request: c2.req.raw
79659
+ };
79660
+ try {
79661
+ const result = await listGameItems(ctx);
79662
+ return c2.json(result);
79663
+ } catch (error2) {
79664
+ if (error2 instanceof ApiError) {
79665
+ return c2.json({ error: error2.message }, error2.statusCode);
79666
+ }
79667
+ console.error("Error in listGameItems:", error2);
79668
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
79669
+ return c2.json({ error: message2 }, 500);
79670
+ }
79671
+ });
79672
+ gamesRouter.post("/:gameId/items", async (c2) => {
79673
+ const gameId = c2.req.param("gameId");
79674
+ const ctx = {
79675
+ user: c2.get("user"),
79676
+ params: { gameId },
79677
+ url: new URL(c2.req.url),
79678
+ request: c2.req.raw
79679
+ };
79680
+ try {
79681
+ const result = await createGameItem(ctx);
79682
+ return c2.json(result, 201);
79683
+ } catch (error2) {
79684
+ if (error2 instanceof ApiError) {
79685
+ return c2.json({ error: error2.message }, error2.statusCode);
79686
+ }
79687
+ console.error("Error in createGameItem:", error2);
79688
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
79689
+ return c2.json({ error: message2 }, 500);
79690
+ }
79691
+ });
79692
+ gamesRouter.patch("/:gameId/items/:itemId", async (c2) => {
79693
+ const gameId = c2.req.param("gameId");
79694
+ const itemId = c2.req.param("itemId");
79695
+ const ctx = {
79696
+ user: c2.get("user"),
79697
+ params: { gameId, itemId },
79698
+ url: new URL(c2.req.url),
79699
+ request: c2.req.raw
79700
+ };
79701
+ try {
79702
+ const result = await updateGameItem(ctx);
79703
+ return c2.json(result);
79704
+ } catch (error2) {
79705
+ if (error2 instanceof ApiError) {
79706
+ return c2.json({ error: error2.message }, error2.statusCode);
79707
+ }
79708
+ console.error("Error in updateGameItem:", error2);
79709
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
79710
+ return c2.json({ error: message2 }, 500);
79711
+ }
79712
+ });
79713
+ gamesRouter.delete("/:gameId/items/:itemId", async (c2) => {
79714
+ const gameId = c2.req.param("gameId");
79715
+ const itemId = c2.req.param("itemId");
79716
+ const ctx = {
79717
+ user: c2.get("user"),
79718
+ params: { gameId, itemId },
79719
+ url: new URL(c2.req.url),
79720
+ request: c2.req.raw
79721
+ };
79722
+ try {
79723
+ await deleteGameItem(ctx);
79724
+ return c2.body(null, 204);
79725
+ } catch (error2) {
79726
+ if (error2 instanceof ApiError) {
79727
+ return c2.json({ error: error2.message }, error2.statusCode);
79728
+ }
79729
+ console.error("Error in deleteGameItem:", error2);
79730
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
79731
+ return c2.json({ error: message2 }, 500);
79732
+ }
79733
+ });
79259
79734
  // src/routes/manifest.ts
79260
79735
  var manifestRouter = new Hono2;
79261
79736
  manifestRouter.get("/", async (c2) => {
@@ -79387,157 +79862,27 @@ shopRouter.get("/view", async (c2) => {
79387
79862
  return c2.json({ error: message2 }, 500);
79388
79863
  }
79389
79864
  });
79390
- // ../api-core/src/items/index.ts
79391
- async function listItems(ctx) {
79392
- const user = ctx.user;
79393
- if (!user) {
79394
- throw ApiError.unauthorized("Must be logged in to view items");
79395
- }
79396
- try {
79397
- const db = getDatabase();
79398
- const allItems = await db.query.items.findMany();
79399
- return allItems;
79400
- } catch (error2) {
79401
- if (error2 instanceof ApiError) {
79402
- throw error2;
79403
- }
79404
- logger2.error("Error fetching items:", error2);
79405
- throw ApiError.internal("Internal server error", error2);
79406
- }
79407
- }
79408
- async function getItemById(ctx) {
79409
- const user = ctx.user;
79410
- const itemId = ctx.params.itemId;
79411
- if (!user) {
79412
- throw ApiError.unauthorized("Must be logged in to view item details");
79413
- }
79414
- if (!itemId) {
79415
- throw ApiError.badRequest("Missing item ID");
79416
- }
79417
- try {
79418
- const db = getDatabase();
79419
- const item = await db.query.items.findFirst({
79420
- where: eq(items.id, itemId)
79421
- });
79422
- if (!item) {
79423
- throw ApiError.notFound("Item not found");
79424
- }
79425
- return item;
79426
- } catch (error2) {
79427
- if (error2 instanceof ApiError) {
79428
- throw error2;
79429
- }
79430
- logger2.error(`Error fetching item ${itemId}:`, error2);
79431
- throw ApiError.internal("Internal server error", error2);
79432
- }
79433
- }
79434
- async function createItem(ctx) {
79435
- const user = ctx.user;
79436
- if (!user || user.role !== "admin") {
79437
- throw ApiError.forbidden("Admin access required");
79438
- }
79439
- let inputData;
79440
- try {
79441
- const requestBody = await ctx.request.json();
79442
- const validationResult = InsertItemSchema.safeParse(requestBody);
79443
- if (!validationResult.success) {
79444
- throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
79445
- }
79446
- inputData = validationResult.data;
79447
- } catch (error2) {
79448
- if (error2 instanceof ApiError) {
79449
- throw error2;
79450
- }
79451
- logger2.error("Failed to parse request body or invalid JSON:", error2);
79452
- throw ApiError.badRequest("Invalid JSON body");
79453
- }
79454
- try {
79455
- const db = getDatabase();
79456
- const [newItem] = await db.insert(items).values(inputData).returning();
79457
- if (!newItem) {
79458
- throw ApiError.internal("Failed to create item in database");
79459
- }
79460
- return newItem;
79461
- } catch (error2) {
79462
- if (error2 instanceof Error) {
79463
- if (error2.message.includes("duplicate key value violates unique constraint")) {
79464
- throw ApiError.conflict("An item with this internal name already exists");
79465
- }
79466
- }
79467
- logger2.error("Error creating item:", error2);
79468
- throw ApiError.internal("Internal server error", error2);
79469
- }
79470
- }
79471
- async function updateItem(ctx) {
79472
- const user = ctx.user;
79473
- const itemId = ctx.params.itemId;
79474
- if (!user || user.role !== "admin") {
79475
- throw ApiError.forbidden("Admin access required");
79476
- }
79477
- if (!itemId) {
79478
- throw ApiError.badRequest("Missing item ID");
79479
- }
79480
- let inputData;
79481
- try {
79482
- const requestBody = await ctx.request.json();
79483
- const validationResult = UpdateItemSchema.safeParse(requestBody);
79484
- if (!validationResult.success) {
79485
- throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
79486
- }
79487
- inputData = validationResult.data;
79488
- } catch (error2) {
79489
- if (error2 instanceof ApiError) {
79490
- throw error2;
79491
- }
79492
- logger2.error("Failed to parse request body or invalid JSON:", error2);
79493
- throw ApiError.badRequest("Invalid JSON body");
79494
- }
79495
- if (Object.keys(inputData).length === 0) {
79496
- throw ApiError.badRequest("No update data provided");
79497
- }
79498
- try {
79499
- const db = getDatabase();
79500
- const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
79501
- if (!updatedItem) {
79502
- throw ApiError.notFound("Item not found for update");
79503
- }
79504
- return updatedItem;
79505
- } catch (error2) {
79506
- if (error2 instanceof Error) {
79507
- if (error2.message.includes("duplicate key value violates unique constraint")) {
79508
- throw ApiError.conflict("An item with this internal name already exists");
79509
- }
79510
- }
79511
- logger2.error(`Error updating item ${itemId}:`, error2);
79512
- throw ApiError.internal("Internal server error", error2);
79513
- }
79514
- }
79515
- async function deleteItem(ctx) {
79516
- const user = ctx.user;
79517
- const itemId = ctx.params.itemId;
79518
- if (!user || user.role !== "admin") {
79519
- throw ApiError.forbidden("Admin access required");
79520
- }
79521
- if (!itemId) {
79522
- throw ApiError.badRequest("Missing item ID");
79523
- }
79865
+ // src/routes/items.ts
79866
+ var itemsRouter = new Hono2;
79867
+ itemsRouter.get("/resolve", async (c2) => {
79868
+ const ctx = {
79869
+ user: c2.get("user"),
79870
+ params: {},
79871
+ url: new URL(c2.req.url),
79872
+ request: c2.req.raw
79873
+ };
79524
79874
  try {
79525
- const db = getDatabase();
79526
- const result = await db.delete(items).where(eq(items.id, itemId)).returning({ id: items.id });
79527
- if (result.length === 0) {
79528
- throw ApiError.notFound("Item not found for deletion");
79529
- }
79875
+ const result = await resolveItem(ctx);
79876
+ return c2.json(result);
79530
79877
  } catch (error2) {
79531
79878
  if (error2 instanceof ApiError) {
79532
- throw error2;
79879
+ return c2.json({ error: error2.message }, error2.statusCode);
79533
79880
  }
79534
- logger2.error(`Error deleting item ${itemId}:`, error2);
79535
- throw ApiError.internal("Internal server error", error2);
79881
+ console.error("Error in resolveItem:", error2);
79882
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
79883
+ return c2.json({ error: message2 }, 500);
79536
79884
  }
79537
- }
79538
-
79539
- // src/routes/items.ts
79540
- var itemsRouter = new Hono2;
79885
+ });
79541
79886
  itemsRouter.post("/", async (c2) => {
79542
79887
  const ctx = {
79543
79888
  user: c2.get("user"),
@@ -79710,8 +80055,8 @@ async function createCurrency(ctx) {
79710
80055
  } catch (error2) {
79711
80056
  if (error2 instanceof Error) {
79712
80057
  if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
79713
- if (error2.message.includes("currencies_internal_name_unique")) {
79714
- throw ApiError.conflict("A currency with this internal name already exists");
80058
+ if (error2.message.includes("currencies_slug_unique")) {
80059
+ throw ApiError.conflict("A currency with this slug already exists");
79715
80060
  }
79716
80061
  throw ApiError.conflict("A similar currency already exists");
79717
80062
  }
@@ -79757,8 +80102,8 @@ async function updateCurrency(ctx) {
79757
80102
  } catch (error2) {
79758
80103
  if (error2 instanceof Error) {
79759
80104
  if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
79760
- if (error2.message.includes("currencies_internal_name_unique")) {
79761
- throw ApiError.conflict("A currency with this internal name already exists");
80105
+ if (error2.message.includes("currencies_slug_unique")) {
80106
+ throw ApiError.conflict("A currency with this slug already exists");
79762
80107
  }
79763
80108
  throw ApiError.conflict("A similar currency already exists");
79764
80109
  }