@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/cli.js CHANGED
@@ -52853,7 +52853,8 @@ var PLAYCADEMY_CREDITS_ID = crypto.randomUUID();
52853
52853
  var SAMPLE_ITEMS = [
52854
52854
  {
52855
52855
  id: PLAYCADEMY_CREDITS_ID,
52856
- internalName: "PLAYCADEMY_CREDITS",
52856
+ slug: "PLAYCADEMY_CREDITS",
52857
+ gameId: null,
52857
52858
  displayName: "PLAYCADEMY credits",
52858
52859
  description: "The main currency used across PLAYCADEMY.",
52859
52860
  type: "currency",
@@ -52864,7 +52865,8 @@ var SAMPLE_ITEMS = [
52864
52865
  },
52865
52866
  {
52866
52867
  id: crypto.randomUUID(),
52867
- internalName: "FOUNDING_MEMBER_BADGE",
52868
+ slug: "FOUNDING_MEMBER_BADGE",
52869
+ gameId: null,
52868
52870
  displayName: "Founding Member Badge",
52869
52871
  description: "Reserved for founding core team of the PLAYCADEMY platform.",
52870
52872
  type: "badge",
@@ -52875,7 +52877,8 @@ var SAMPLE_ITEMS = [
52875
52877
  },
52876
52878
  {
52877
52879
  id: crypto.randomUUID(),
52878
- internalName: "EARLY_ADOPTER_BADGE",
52880
+ slug: "EARLY_ADOPTER_BADGE",
52881
+ gameId: null,
52879
52882
  displayName: "Early Adopter Badge",
52880
52883
  description: "Awarded to users who joined during the beta phase.",
52881
52884
  type: "badge",
@@ -52886,7 +52889,8 @@ var SAMPLE_ITEMS = [
52886
52889
  },
52887
52890
  {
52888
52891
  id: crypto.randomUUID(),
52889
- internalName: "FIRST_GAME_BADGE",
52892
+ slug: "FIRST_GAME_BADGE",
52893
+ gameId: null,
52890
52894
  displayName: "First Game Played",
52891
52895
  description: "Awarded for playing your first game in the Playcademy platform.",
52892
52896
  type: "badge",
@@ -52897,7 +52901,8 @@ var SAMPLE_ITEMS = [
52897
52901
  },
52898
52902
  {
52899
52903
  id: crypto.randomUUID(),
52900
- internalName: "COMMON_SWORD",
52904
+ slug: "COMMON_SWORD",
52905
+ gameId: null,
52901
52906
  displayName: "Common Sword",
52902
52907
  description: "A basic sword, good for beginners.",
52903
52908
  type: "unlock",
@@ -52906,7 +52911,8 @@ var SAMPLE_ITEMS = [
52906
52911
  },
52907
52912
  {
52908
52913
  id: crypto.randomUUID(),
52909
- internalName: "SMALL_HEALTH_POTION",
52914
+ slug: "SMALL_HEALTH_POTION",
52915
+ gameId: null,
52910
52916
  displayName: "Small Health Potion",
52911
52917
  description: "Restores a small amount of health.",
52912
52918
  type: "other",
@@ -52915,7 +52921,8 @@ var SAMPLE_ITEMS = [
52915
52921
  },
52916
52922
  {
52917
52923
  id: crypto.randomUUID(),
52918
- internalName: "SMALL_BACKPACK",
52924
+ slug: "SMALL_BACKPACK",
52925
+ gameId: null,
52919
52926
  displayName: "Small Backpack",
52920
52927
  description: "Increases your inventory capacity by 5 slots.",
52921
52928
  type: "upgrade",
@@ -77388,14 +77395,20 @@ var itemTypeEnum = pgEnum("item_type", [
77388
77395
  ]);
77389
77396
  var items = pgTable("items", {
77390
77397
  id: uuid("id").primaryKey().defaultRandom(),
77391
- internalName: text("internal_name").notNull().unique(),
77398
+ slug: text("slug").notNull(),
77399
+ gameId: uuid("game_id").references(() => games.id, {
77400
+ onDelete: "cascade"
77401
+ }),
77392
77402
  displayName: text("display_name").notNull(),
77393
77403
  description: text("description"),
77394
77404
  type: itemTypeEnum("type").notNull().default("other"),
77395
77405
  imageUrl: text("image_url"),
77396
77406
  metadata: jsonb("metadata").default({}),
77397
77407
  createdAt: timestamp("created_at").defaultNow().notNull()
77398
- });
77408
+ }, (table) => [
77409
+ uniqueIndex("items_game_slug_idx").on(table.gameId, table.slug),
77410
+ uniqueIndex("items_global_slug_idx").on(table.slug).where(sql`game_id IS NULL`)
77411
+ ]);
77399
77412
  var inventoryItems = pgTable("inventory_items", {
77400
77413
  id: uuid("id").primaryKey().defaultRandom(),
77401
77414
  userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
@@ -77428,9 +77441,13 @@ var shopListings = pgTable("shop_listings", {
77428
77441
  }, (table) => [
77429
77442
  uniqueIndex("unique_item_currency_listing_idx").on(table.itemId, table.currencyId)
77430
77443
  ]);
77431
- var itemsRelations = relations(items, ({ many }) => ({
77444
+ var itemsRelations = relations(items, ({ many, one }) => ({
77432
77445
  shopListings: many(shopListings),
77433
- inventoryItems: many(inventoryItems)
77446
+ inventoryItems: many(inventoryItems),
77447
+ game: one(games, {
77448
+ fields: [items.gameId],
77449
+ references: [games.id]
77450
+ })
77434
77451
  }));
77435
77452
  var currenciesRelations = relations(currencies, ({ many }) => ({
77436
77453
  shopListings: many(shopListings)
@@ -77479,14 +77496,18 @@ var ItemMetadataSchema = exports_external.object({
77479
77496
  var InsertItemSchema = createInsertSchema(items, {
77480
77497
  imageUrl: exports_external.string().refine((val) => validateRelativePath2(val, "imageUrl")).optional().nullable(),
77481
77498
  type: exports_external.enum(itemTypeEnum.enumValues).default("other"),
77482
- metadata: ItemMetadataSchema.optional()
77499
+ metadata: ItemMetadataSchema.optional(),
77500
+ gameId: exports_external.string().uuid().optional().nullable()
77483
77501
  }).omit({ id: true });
77484
77502
  var SelectItemSchema = createSelectSchema(items);
77485
77503
  var UpdateItemSchema = InsertItemSchema.pick({
77504
+ slug: true,
77505
+ displayName: true,
77506
+ description: true,
77486
77507
  type: true,
77487
77508
  metadata: true,
77488
77509
  imageUrl: true
77489
- });
77510
+ }).partial();
77490
77511
  var InsertInventoryItemSchema = createInsertSchema(inventoryItems).omit({
77491
77512
  id: true,
77492
77513
  updatedAt: true
@@ -77722,7 +77743,7 @@ async function seedCurrentProjectGame(db, project) {
77722
77743
  // package.json
77723
77744
  var package_default = {
77724
77745
  name: "@playcademy/sandbox",
77725
- version: "0.1.0-beta.6",
77746
+ version: "0.1.0-beta.7",
77726
77747
  description: "Local development server for Playcademy game development",
77727
77748
  type: "module",
77728
77749
  exports: {
@@ -77827,7 +77848,7 @@ async function getUserMe(ctx) {
77827
77848
  }
77828
77849
 
77829
77850
  // ../data/src/constants.ts
77830
- var ITEM_INTERNAL_NAMES = {
77851
+ var ITEM_SLUGS = {
77831
77852
  PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
77832
77853
  PLAYCADEMY_XP: "PLAYCADEMY_XP",
77833
77854
  FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
@@ -77838,14 +77859,15 @@ var ITEM_INTERNAL_NAMES = {
77838
77859
  SMALL_BACKPACK: "SMALL_BACKPACK"
77839
77860
  };
77840
77861
  var CURRENCIES = {
77841
- PRIMARY: ITEM_INTERNAL_NAMES.PLAYCADEMY_CREDITS,
77842
- XP: ITEM_INTERNAL_NAMES.PLAYCADEMY_XP
77862
+ PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
77863
+ XP: ITEM_SLUGS.PLAYCADEMY_XP
77843
77864
  };
77844
77865
  var BADGES = {
77845
- FOUNDING_MEMBER: ITEM_INTERNAL_NAMES.FOUNDING_MEMBER_BADGE,
77846
- EARLY_ADOPTER: ITEM_INTERNAL_NAMES.EARLY_ADOPTER_BADGE,
77847
- FIRST_GAME: ITEM_INTERNAL_NAMES.FIRST_GAME_BADGE
77866
+ FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
77867
+ EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
77868
+ FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
77848
77869
  };
77870
+ var INTERACTION_TYPE = Object.fromEntries(interactionTypeEnum.enumValues.map((value) => [value, value]));
77849
77871
 
77850
77872
  // ../api-core/src/utils/levels.ts
77851
77873
  var levelConfigCache = null;
@@ -78002,7 +78024,7 @@ async function addXP(ctx, amount) {
78002
78024
  creditsAwarded: creditsToAward
78003
78025
  });
78004
78026
  if (creditsToAward > 0) {
78005
- const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.internalName, CURRENCIES.PRIMARY)).limit(1);
78027
+ const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
78006
78028
  if (!creditsItem) {
78007
78029
  throw ApiError.internal(`${CURRENCIES.PRIMARY} item not found`);
78008
78030
  }
@@ -78202,15 +78224,18 @@ async function getUserInventory(ctx) {
78202
78224
  const db = getDatabase();
78203
78225
  const inventory2 = await db.select({
78204
78226
  id: inventoryItems.id,
78227
+ userId: inventoryItems.userId,
78205
78228
  quantity: inventoryItems.quantity,
78206
78229
  item: {
78207
78230
  id: items.id,
78208
- internalName: items.internalName,
78231
+ slug: items.slug,
78232
+ gameId: items.gameId,
78209
78233
  displayName: items.displayName,
78210
78234
  description: items.description,
78211
78235
  type: items.type,
78212
78236
  imageUrl: items.imageUrl,
78213
- metadata: items.metadata
78237
+ metadata: items.metadata,
78238
+ createdAt: items.createdAt
78214
78239
  },
78215
78240
  updatedAt: inventoryItems.updatedAt
78216
78241
  }).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
@@ -79839,14 +79864,13 @@ async function listGames(ctx) {
79839
79864
  if (!user) {
79840
79865
  throw ApiError.unauthorized("Must be logged in to list games");
79841
79866
  }
79842
- if (user.role !== "admin" && user.role !== "developer") {
79843
- throw ApiError.forbidden("Requires admin or developer privileges to list games");
79844
- }
79845
79867
  try {
79846
79868
  const db = getDatabase();
79847
79869
  let filter2 = undefined;
79848
79870
  if (user.role === "developer") {
79849
79871
  filter2 = eq(games.developerId, user.id);
79872
+ } else if (user.role === "player") {
79873
+ return [];
79850
79874
  }
79851
79875
  const games2 = await db.query.games.findMany({
79852
79876
  where: filter2,
@@ -80087,144 +80111,513 @@ async function upsertGameBySlug(ctx) {
80087
80111
  throw ApiError.internal("Internal server error", error2);
80088
80112
  }
80089
80113
  }
80090
- // ../../node_modules/@oslojs/binary/dist/uint.js
80091
- class BigEndian {
80092
- uint8(data2, offset) {
80093
- if (data2.byteLength < offset + 1) {
80094
- throw new TypeError("Insufficient bytes");
80095
- }
80096
- return data2[offset];
80097
- }
80098
- uint16(data2, offset) {
80099
- if (data2.byteLength < offset + 2) {
80100
- throw new TypeError("Insufficient bytes");
80101
- }
80102
- return data2[offset] << 8 | data2[offset + 1];
80114
+
80115
+ // ../api-core/src/items/index.ts
80116
+ async function validateGameOwnership(user, gameId) {
80117
+ if (user.role === "admin") {
80118
+ return;
80103
80119
  }
80104
- uint32(data2, offset) {
80105
- if (data2.byteLength < offset + 4) {
80106
- throw new TypeError("Insufficient bytes");
80120
+ try {
80121
+ const db = getDatabase();
80122
+ const gameOwnership = await db.query.games.findFirst({
80123
+ where: and(eq(games.id, gameId), eq(games.developerId, user.id)),
80124
+ columns: { id: true }
80125
+ });
80126
+ if (!gameOwnership) {
80127
+ const gameExists = await db.query.games.findFirst({
80128
+ where: eq(games.id, gameId),
80129
+ columns: { id: true }
80130
+ });
80131
+ if (!gameExists) {
80132
+ throw ApiError.notFound("Game not found");
80133
+ }
80134
+ throw ApiError.forbidden("You do not own this game");
80107
80135
  }
80108
- let result = 0;
80109
- for (let i3 = 0;i3 < 4; i3++) {
80110
- result |= data2[offset + i3] << 24 - i3 * 8;
80136
+ } catch (error2) {
80137
+ if (error2 instanceof ApiError) {
80138
+ throw error2;
80111
80139
  }
80112
- return result;
80140
+ logger2.error(`Error checking game ownership for ${gameId}:`, error2);
80141
+ throw ApiError.internal("Internal server error", error2);
80113
80142
  }
80114
- uint64(data2, offset) {
80115
- if (data2.byteLength < offset + 8) {
80116
- throw new TypeError("Insufficient bytes");
80117
- }
80118
- let result = 0n;
80119
- for (let i3 = 0;i3 < 8; i3++) {
80120
- result |= BigInt(data2[offset + i3]) << BigInt(56 - i3 * 8);
80121
- }
80122
- return result;
80143
+ }
80144
+ async function listItems(ctx) {
80145
+ const user = ctx.user;
80146
+ if (!user) {
80147
+ throw ApiError.unauthorized("Must be logged in to view items");
80123
80148
  }
80124
- putUint8(target, value, offset) {
80125
- if (target.length < offset + 1) {
80126
- throw new TypeError("Not enough space");
80149
+ try {
80150
+ const db = getDatabase();
80151
+ const url2 = new URL(ctx.request.url);
80152
+ const gameId = url2.searchParams.get("gameId");
80153
+ let allItems;
80154
+ if (gameId) {
80155
+ allItems = await db.query.items.findMany({
80156
+ where: eq(items.gameId, gameId)
80157
+ });
80158
+ } else {
80159
+ allItems = await db.query.items.findMany();
80127
80160
  }
80128
- if (value < 0 || value > 255) {
80129
- throw new TypeError("Invalid uint8 value");
80161
+ return allItems;
80162
+ } catch (error2) {
80163
+ if (error2 instanceof ApiError) {
80164
+ throw error2;
80130
80165
  }
80131
- target[offset] = value;
80166
+ logger2.error("Error fetching items:", error2);
80167
+ throw ApiError.internal("Internal server error", error2);
80132
80168
  }
80133
- putUint16(target, value, offset) {
80134
- if (target.length < offset + 2) {
80135
- throw new TypeError("Not enough space");
80169
+ }
80170
+ async function getItemById(ctx) {
80171
+ const user = ctx.user;
80172
+ const itemId = ctx.params.itemId;
80173
+ if (!user) {
80174
+ throw ApiError.unauthorized("Must be logged in to view item details");
80175
+ }
80176
+ if (!itemId) {
80177
+ throw ApiError.badRequest("Missing item ID");
80178
+ }
80179
+ try {
80180
+ const db = getDatabase();
80181
+ const item = await db.query.items.findFirst({
80182
+ where: eq(items.id, itemId)
80183
+ });
80184
+ if (!item) {
80185
+ throw ApiError.notFound("Item not found");
80136
80186
  }
80137
- if (value < 0 || value > 65535) {
80138
- throw new TypeError("Invalid uint16 value");
80187
+ return item;
80188
+ } catch (error2) {
80189
+ if (error2 instanceof ApiError) {
80190
+ throw error2;
80139
80191
  }
80140
- target[offset] = value >> 8;
80141
- target[offset + 1] = value & 255;
80192
+ logger2.error(`Error fetching item ${itemId}:`, error2);
80193
+ throw ApiError.internal("Internal server error", error2);
80142
80194
  }
80143
- putUint32(target, value, offset) {
80144
- if (target.length < offset + 4) {
80145
- throw new TypeError("Not enough space");
80146
- }
80147
- if (value < 0 || value > 4294967295) {
80148
- throw new TypeError("Invalid uint32 value");
80195
+ }
80196
+ async function createItem(ctx) {
80197
+ const user = ctx.user;
80198
+ if (!user || user.role !== "admin") {
80199
+ throw ApiError.forbidden("Admin access required");
80200
+ }
80201
+ let inputData;
80202
+ try {
80203
+ const requestBody = await ctx.request.json();
80204
+ const validationResult = InsertItemSchema.safeParse(requestBody);
80205
+ if (!validationResult.success) {
80206
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
80149
80207
  }
80150
- for (let i3 = 0;i3 < 4; i3++) {
80151
- target[offset + i3] = value >> (3 - i3) * 8 & 255;
80208
+ inputData = validationResult.data;
80209
+ } catch (error2) {
80210
+ if (error2 instanceof ApiError) {
80211
+ throw error2;
80152
80212
  }
80213
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
80214
+ throw ApiError.badRequest("Invalid JSON body");
80153
80215
  }
80154
- putUint64(target, value, offset) {
80155
- if (target.length < offset + 8) {
80156
- throw new TypeError("Not enough space");
80157
- }
80158
- if (value < 0 || value > 18446744073709551615n) {
80159
- throw new TypeError("Invalid uint64 value");
80216
+ try {
80217
+ const db = getDatabase();
80218
+ const [newItem] = await db.insert(items).values(inputData).returning();
80219
+ if (!newItem) {
80220
+ throw ApiError.internal("Failed to create item in database");
80160
80221
  }
80161
- for (let i3 = 0;i3 < 8; i3++) {
80162
- target[offset + i3] = Number(value >> BigInt((7 - i3) * 8) & 0xffn);
80222
+ return newItem;
80223
+ } catch (error2) {
80224
+ if (error2 instanceof Error) {
80225
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
80226
+ const gameScope = inputData.gameId ? "for this game" : "as a platform item";
80227
+ throw ApiError.conflict(`An item with slug '${inputData.slug}' already exists ${gameScope}`);
80228
+ }
80163
80229
  }
80230
+ logger2.error("Error creating item:", error2);
80231
+ throw ApiError.internal("Internal server error", error2);
80164
80232
  }
80165
80233
  }
80166
-
80167
- class LittleEndian {
80168
- uint8(data2, offset) {
80169
- if (data2.byteLength < offset + 1) {
80170
- throw new TypeError("Insufficient bytes");
80171
- }
80172
- return data2[offset];
80234
+ async function updateItem(ctx) {
80235
+ const user = ctx.user;
80236
+ const itemId = ctx.params.itemId;
80237
+ if (!user || user.role !== "admin") {
80238
+ throw ApiError.forbidden("Admin access required");
80173
80239
  }
80174
- uint16(data2, offset) {
80175
- if (data2.byteLength < offset + 2) {
80176
- throw new TypeError("Insufficient bytes");
80177
- }
80178
- return data2[offset] | data2[offset + 1] << 8;
80240
+ if (!itemId) {
80241
+ throw ApiError.badRequest("Missing item ID");
80179
80242
  }
80180
- uint32(data2, offset) {
80181
- if (data2.byteLength < offset + 4) {
80182
- throw new TypeError("Insufficient bytes");
80243
+ let inputData;
80244
+ try {
80245
+ const requestBody = await ctx.request.json();
80246
+ const validationResult = UpdateItemSchema.safeParse(requestBody);
80247
+ if (!validationResult.success) {
80248
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
80183
80249
  }
80184
- let result = 0;
80185
- for (let i3 = 0;i3 < 4; i3++) {
80186
- result |= data2[offset + i3] << i3 * 8;
80250
+ inputData = validationResult.data;
80251
+ } catch (error2) {
80252
+ if (error2 instanceof ApiError) {
80253
+ throw error2;
80187
80254
  }
80188
- return result;
80255
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
80256
+ throw ApiError.badRequest("Invalid JSON body");
80189
80257
  }
80190
- uint64(data2, offset) {
80191
- if (data2.byteLength < offset + 8) {
80192
- throw new TypeError("Insufficient bytes");
80193
- }
80194
- let result = 0n;
80195
- for (let i3 = 0;i3 < 8; i3++) {
80196
- result |= BigInt(data2[offset + i3]) << BigInt(i3 * 8);
80197
- }
80198
- return result;
80258
+ if (Object.keys(inputData).length === 0) {
80259
+ throw ApiError.badRequest("No update data provided");
80199
80260
  }
80200
- putUint8(target, value, offset) {
80201
- if (target.length < 1 + offset) {
80202
- throw new TypeError("Insufficient space");
80261
+ try {
80262
+ const db = getDatabase();
80263
+ const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
80264
+ if (!updatedItem) {
80265
+ throw ApiError.notFound("Item not found for update");
80203
80266
  }
80204
- if (value < 0 || value > 255) {
80205
- throw new TypeError("Invalid uint8 value");
80267
+ return updatedItem;
80268
+ } catch (error2) {
80269
+ if (error2 instanceof Error) {
80270
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
80271
+ throw ApiError.conflict("An item with this slug already exists within the same scope (platform or game)");
80272
+ }
80206
80273
  }
80207
- target[offset] = value;
80274
+ logger2.error(`Error updating item ${itemId}:`, error2);
80275
+ throw ApiError.internal("Internal server error", error2);
80208
80276
  }
80209
- putUint16(target, value, offset) {
80210
- if (target.length < 2 + offset) {
80211
- throw new TypeError("Insufficient space");
80212
- }
80213
- if (value < 0 || value > 65535) {
80214
- throw new TypeError("Invalid uint16 value");
80215
- }
80216
- target[offset + 1] = value >> 8;
80217
- target[offset] = value & 255;
80277
+ }
80278
+ async function deleteItem(ctx) {
80279
+ const user = ctx.user;
80280
+ const itemId = ctx.params.itemId;
80281
+ if (!user || user.role !== "admin") {
80282
+ throw ApiError.forbidden("Admin access required");
80218
80283
  }
80219
- putUint32(target, value, offset) {
80220
- if (target.length < 4 + offset) {
80221
- throw new TypeError("Insufficient space");
80222
- }
80223
- if (value < 0 || value > 4294967295) {
80224
- throw new TypeError("Invalid uint32 value");
80284
+ if (!itemId) {
80285
+ throw ApiError.badRequest("Missing item ID");
80286
+ }
80287
+ try {
80288
+ const db = getDatabase();
80289
+ const result = await db.delete(items).where(eq(items.id, itemId)).returning({ id: items.id });
80290
+ if (result.length === 0) {
80291
+ throw ApiError.notFound("Item not found for deletion");
80225
80292
  }
80226
- for (let i3 = 0;i3 < 4; i3++) {
80227
- target[offset + i3] = value >> i3 * 8 & 255;
80293
+ } catch (error2) {
80294
+ if (error2 instanceof ApiError) {
80295
+ throw error2;
80296
+ }
80297
+ logger2.error(`Error deleting item ${itemId}:`, error2);
80298
+ throw ApiError.internal("Internal server error", error2);
80299
+ }
80300
+ }
80301
+ async function resolveItem(ctx) {
80302
+ const user = ctx.user;
80303
+ const url2 = new URL(ctx.request.url);
80304
+ const slug = url2.searchParams.get("slug");
80305
+ const gameId = url2.searchParams.get("gameId");
80306
+ if (!user) {
80307
+ throw ApiError.unauthorized("Must be logged in to resolve items");
80308
+ }
80309
+ if (!slug) {
80310
+ throw ApiError.badRequest("Missing slug parameter");
80311
+ }
80312
+ try {
80313
+ const db = getDatabase();
80314
+ if (gameId) {
80315
+ const gameItem = await db.query.items.findFirst({
80316
+ where: and(eq(items.slug, slug), eq(items.gameId, gameId))
80317
+ });
80318
+ if (gameItem) {
80319
+ return gameItem;
80320
+ }
80321
+ }
80322
+ const platformItem = await db.query.items.findFirst({
80323
+ where: and(eq(items.slug, slug), isNull(items.gameId))
80324
+ });
80325
+ if (!platformItem) {
80326
+ throw ApiError.notFound(`Item with slug '${slug}' not found`);
80327
+ }
80328
+ return platformItem;
80329
+ } catch (error2) {
80330
+ if (error2 instanceof ApiError) {
80331
+ throw error2;
80332
+ }
80333
+ logger2.error(`Error resolving item slug ${slug}:`, error2);
80334
+ throw ApiError.internal("Internal server error", error2);
80335
+ }
80336
+ }
80337
+ async function listGameItems(ctx) {
80338
+ const user = ctx.user;
80339
+ const gameId = ctx.params.gameId;
80340
+ if (!user) {
80341
+ throw ApiError.unauthorized("Must be logged in to view items");
80342
+ }
80343
+ if (!gameId) {
80344
+ throw ApiError.badRequest("Missing game ID");
80345
+ }
80346
+ try {
80347
+ const db = getDatabase();
80348
+ const gameItems = await db.query.items.findMany({
80349
+ where: eq(items.gameId, gameId)
80350
+ });
80351
+ return gameItems;
80352
+ } catch (error2) {
80353
+ if (error2 instanceof ApiError) {
80354
+ throw error2;
80355
+ }
80356
+ logger2.error(`Error fetching items for game ${gameId}:`, error2);
80357
+ throw ApiError.internal("Internal server error", error2);
80358
+ }
80359
+ }
80360
+ async function createGameItem(ctx) {
80361
+ const user = ctx.user;
80362
+ const gameId = ctx.params.gameId;
80363
+ if (!user) {
80364
+ throw ApiError.unauthorized("Must be logged in to create items");
80365
+ }
80366
+ if (!gameId) {
80367
+ throw ApiError.badRequest("Missing game ID");
80368
+ }
80369
+ await validateGameOwnership(user, gameId);
80370
+ let inputData;
80371
+ try {
80372
+ const requestBody = await ctx.request.json();
80373
+ const bodyData = typeof requestBody === "object" && requestBody !== null ? requestBody : {};
80374
+ const validationResult = InsertItemSchema.safeParse({
80375
+ ...bodyData,
80376
+ gameId
80377
+ });
80378
+ if (!validationResult.success) {
80379
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
80380
+ }
80381
+ inputData = validationResult.data;
80382
+ } catch (error2) {
80383
+ if (error2 instanceof ApiError) {
80384
+ throw error2;
80385
+ }
80386
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
80387
+ throw ApiError.badRequest("Invalid JSON body");
80388
+ }
80389
+ try {
80390
+ const db = getDatabase();
80391
+ const [newItem] = await db.insert(items).values(inputData).returning();
80392
+ if (!newItem) {
80393
+ throw ApiError.internal("Failed to create item in database");
80394
+ }
80395
+ return newItem;
80396
+ } catch (error2) {
80397
+ if (error2 instanceof Error) {
80398
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
80399
+ throw ApiError.conflict(`An item with slug '${inputData.slug}' already exists for this game`);
80400
+ }
80401
+ }
80402
+ logger2.error("Error creating game item:", error2);
80403
+ throw ApiError.internal("Internal server error", error2);
80404
+ }
80405
+ }
80406
+ async function updateGameItem(ctx) {
80407
+ const user = ctx.user;
80408
+ const gameId = ctx.params.gameId;
80409
+ const itemId = ctx.params.itemId;
80410
+ if (!user) {
80411
+ throw ApiError.unauthorized("Must be logged in to update items");
80412
+ }
80413
+ if (!gameId || !itemId) {
80414
+ throw ApiError.badRequest("Missing game ID or item ID");
80415
+ }
80416
+ await validateGameOwnership(user, gameId);
80417
+ let inputData;
80418
+ try {
80419
+ const requestBody = await ctx.request.json();
80420
+ const validationResult = UpdateItemSchema.safeParse(requestBody);
80421
+ if (!validationResult.success) {
80422
+ throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
80423
+ }
80424
+ inputData = validationResult.data;
80425
+ } catch (error2) {
80426
+ if (error2 instanceof ApiError) {
80427
+ throw error2;
80428
+ }
80429
+ logger2.error("Failed to parse request body or invalid JSON:", error2);
80430
+ throw ApiError.badRequest("Invalid JSON body");
80431
+ }
80432
+ if (Object.keys(inputData).length === 0) {
80433
+ throw ApiError.badRequest("No update data provided");
80434
+ }
80435
+ try {
80436
+ const db = getDatabase();
80437
+ const existingItem = await db.query.items.findFirst({
80438
+ where: and(eq(items.id, itemId), eq(items.gameId, gameId))
80439
+ });
80440
+ if (!existingItem) {
80441
+ throw ApiError.notFound("Item not found for this game");
80442
+ }
80443
+ const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
80444
+ if (!updatedItem) {
80445
+ throw ApiError.notFound("Item not found for update");
80446
+ }
80447
+ return updatedItem;
80448
+ } catch (error2) {
80449
+ if (error2 instanceof Error) {
80450
+ if (error2.message.includes("duplicate key value violates unique constraint")) {
80451
+ throw ApiError.conflict("An item with this slug already exists for this game");
80452
+ }
80453
+ }
80454
+ logger2.error(`Error updating game item ${itemId}:`, error2);
80455
+ throw ApiError.internal("Internal server error", error2);
80456
+ }
80457
+ }
80458
+ async function deleteGameItem(ctx) {
80459
+ const user = ctx.user;
80460
+ const gameId = ctx.params.gameId;
80461
+ const itemId = ctx.params.itemId;
80462
+ if (!user) {
80463
+ throw ApiError.unauthorized("Must be logged in to delete items");
80464
+ }
80465
+ if (!gameId || !itemId) {
80466
+ throw ApiError.badRequest("Missing game ID or item ID");
80467
+ }
80468
+ await validateGameOwnership(user, gameId);
80469
+ try {
80470
+ const db = getDatabase();
80471
+ const result = await db.delete(items).where(and(eq(items.id, itemId), eq(items.gameId, gameId))).returning({ id: items.id });
80472
+ if (result.length === 0) {
80473
+ throw ApiError.notFound("Item not found for this game");
80474
+ }
80475
+ } catch (error2) {
80476
+ if (error2 instanceof ApiError) {
80477
+ throw error2;
80478
+ }
80479
+ logger2.error(`Error deleting game item ${itemId}:`, error2);
80480
+ throw ApiError.internal("Internal server error", error2);
80481
+ }
80482
+ }
80483
+ // ../../node_modules/@oslojs/binary/dist/uint.js
80484
+ class BigEndian {
80485
+ uint8(data2, offset) {
80486
+ if (data2.byteLength < offset + 1) {
80487
+ throw new TypeError("Insufficient bytes");
80488
+ }
80489
+ return data2[offset];
80490
+ }
80491
+ uint16(data2, offset) {
80492
+ if (data2.byteLength < offset + 2) {
80493
+ throw new TypeError("Insufficient bytes");
80494
+ }
80495
+ return data2[offset] << 8 | data2[offset + 1];
80496
+ }
80497
+ uint32(data2, offset) {
80498
+ if (data2.byteLength < offset + 4) {
80499
+ throw new TypeError("Insufficient bytes");
80500
+ }
80501
+ let result = 0;
80502
+ for (let i3 = 0;i3 < 4; i3++) {
80503
+ result |= data2[offset + i3] << 24 - i3 * 8;
80504
+ }
80505
+ return result;
80506
+ }
80507
+ uint64(data2, offset) {
80508
+ if (data2.byteLength < offset + 8) {
80509
+ throw new TypeError("Insufficient bytes");
80510
+ }
80511
+ let result = 0n;
80512
+ for (let i3 = 0;i3 < 8; i3++) {
80513
+ result |= BigInt(data2[offset + i3]) << BigInt(56 - i3 * 8);
80514
+ }
80515
+ return result;
80516
+ }
80517
+ putUint8(target, value, offset) {
80518
+ if (target.length < offset + 1) {
80519
+ throw new TypeError("Not enough space");
80520
+ }
80521
+ if (value < 0 || value > 255) {
80522
+ throw new TypeError("Invalid uint8 value");
80523
+ }
80524
+ target[offset] = value;
80525
+ }
80526
+ putUint16(target, value, offset) {
80527
+ if (target.length < offset + 2) {
80528
+ throw new TypeError("Not enough space");
80529
+ }
80530
+ if (value < 0 || value > 65535) {
80531
+ throw new TypeError("Invalid uint16 value");
80532
+ }
80533
+ target[offset] = value >> 8;
80534
+ target[offset + 1] = value & 255;
80535
+ }
80536
+ putUint32(target, value, offset) {
80537
+ if (target.length < offset + 4) {
80538
+ throw new TypeError("Not enough space");
80539
+ }
80540
+ if (value < 0 || value > 4294967295) {
80541
+ throw new TypeError("Invalid uint32 value");
80542
+ }
80543
+ for (let i3 = 0;i3 < 4; i3++) {
80544
+ target[offset + i3] = value >> (3 - i3) * 8 & 255;
80545
+ }
80546
+ }
80547
+ putUint64(target, value, offset) {
80548
+ if (target.length < offset + 8) {
80549
+ throw new TypeError("Not enough space");
80550
+ }
80551
+ if (value < 0 || value > 18446744073709551615n) {
80552
+ throw new TypeError("Invalid uint64 value");
80553
+ }
80554
+ for (let i3 = 0;i3 < 8; i3++) {
80555
+ target[offset + i3] = Number(value >> BigInt((7 - i3) * 8) & 0xffn);
80556
+ }
80557
+ }
80558
+ }
80559
+
80560
+ class LittleEndian {
80561
+ uint8(data2, offset) {
80562
+ if (data2.byteLength < offset + 1) {
80563
+ throw new TypeError("Insufficient bytes");
80564
+ }
80565
+ return data2[offset];
80566
+ }
80567
+ uint16(data2, offset) {
80568
+ if (data2.byteLength < offset + 2) {
80569
+ throw new TypeError("Insufficient bytes");
80570
+ }
80571
+ return data2[offset] | data2[offset + 1] << 8;
80572
+ }
80573
+ uint32(data2, offset) {
80574
+ if (data2.byteLength < offset + 4) {
80575
+ throw new TypeError("Insufficient bytes");
80576
+ }
80577
+ let result = 0;
80578
+ for (let i3 = 0;i3 < 4; i3++) {
80579
+ result |= data2[offset + i3] << i3 * 8;
80580
+ }
80581
+ return result;
80582
+ }
80583
+ uint64(data2, offset) {
80584
+ if (data2.byteLength < offset + 8) {
80585
+ throw new TypeError("Insufficient bytes");
80586
+ }
80587
+ let result = 0n;
80588
+ for (let i3 = 0;i3 < 8; i3++) {
80589
+ result |= BigInt(data2[offset + i3]) << BigInt(i3 * 8);
80590
+ }
80591
+ return result;
80592
+ }
80593
+ putUint8(target, value, offset) {
80594
+ if (target.length < 1 + offset) {
80595
+ throw new TypeError("Insufficient space");
80596
+ }
80597
+ if (value < 0 || value > 255) {
80598
+ throw new TypeError("Invalid uint8 value");
80599
+ }
80600
+ target[offset] = value;
80601
+ }
80602
+ putUint16(target, value, offset) {
80603
+ if (target.length < 2 + offset) {
80604
+ throw new TypeError("Insufficient space");
80605
+ }
80606
+ if (value < 0 || value > 65535) {
80607
+ throw new TypeError("Invalid uint16 value");
80608
+ }
80609
+ target[offset + 1] = value >> 8;
80610
+ target[offset] = value & 255;
80611
+ }
80612
+ putUint32(target, value, offset) {
80613
+ if (target.length < 4 + offset) {
80614
+ throw new TypeError("Insufficient space");
80615
+ }
80616
+ if (value < 0 || value > 4294967295) {
80617
+ throw new TypeError("Invalid uint32 value");
80618
+ }
80619
+ for (let i3 = 0;i3 < 4; i3++) {
80620
+ target[offset + i3] = value >> i3 * 8 & 255;
80228
80621
  }
80229
80622
  }
80230
80623
  putUint64(target, value, offset) {
@@ -81166,6 +81559,88 @@ gamesRouter.post("/uploads/finalize", async (c2) => {
81166
81559
  return c2.json({ error: message2 }, 500);
81167
81560
  }
81168
81561
  });
81562
+ gamesRouter.get("/:gameId/items", async (c2) => {
81563
+ const gameId = c2.req.param("gameId");
81564
+ const ctx = {
81565
+ user: c2.get("user"),
81566
+ params: { gameId },
81567
+ url: new URL(c2.req.url),
81568
+ request: c2.req.raw
81569
+ };
81570
+ try {
81571
+ const result = await listGameItems(ctx);
81572
+ return c2.json(result);
81573
+ } catch (error2) {
81574
+ if (error2 instanceof ApiError) {
81575
+ return c2.json({ error: error2.message }, error2.statusCode);
81576
+ }
81577
+ console.error("Error in listGameItems:", error2);
81578
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
81579
+ return c2.json({ error: message2 }, 500);
81580
+ }
81581
+ });
81582
+ gamesRouter.post("/:gameId/items", async (c2) => {
81583
+ const gameId = c2.req.param("gameId");
81584
+ const ctx = {
81585
+ user: c2.get("user"),
81586
+ params: { gameId },
81587
+ url: new URL(c2.req.url),
81588
+ request: c2.req.raw
81589
+ };
81590
+ try {
81591
+ const result = await createGameItem(ctx);
81592
+ return c2.json(result, 201);
81593
+ } catch (error2) {
81594
+ if (error2 instanceof ApiError) {
81595
+ return c2.json({ error: error2.message }, error2.statusCode);
81596
+ }
81597
+ console.error("Error in createGameItem:", error2);
81598
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
81599
+ return c2.json({ error: message2 }, 500);
81600
+ }
81601
+ });
81602
+ gamesRouter.patch("/:gameId/items/:itemId", async (c2) => {
81603
+ const gameId = c2.req.param("gameId");
81604
+ const itemId = c2.req.param("itemId");
81605
+ const ctx = {
81606
+ user: c2.get("user"),
81607
+ params: { gameId, itemId },
81608
+ url: new URL(c2.req.url),
81609
+ request: c2.req.raw
81610
+ };
81611
+ try {
81612
+ const result = await updateGameItem(ctx);
81613
+ return c2.json(result);
81614
+ } catch (error2) {
81615
+ if (error2 instanceof ApiError) {
81616
+ return c2.json({ error: error2.message }, error2.statusCode);
81617
+ }
81618
+ console.error("Error in updateGameItem:", error2);
81619
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
81620
+ return c2.json({ error: message2 }, 500);
81621
+ }
81622
+ });
81623
+ gamesRouter.delete("/:gameId/items/:itemId", async (c2) => {
81624
+ const gameId = c2.req.param("gameId");
81625
+ const itemId = c2.req.param("itemId");
81626
+ const ctx = {
81627
+ user: c2.get("user"),
81628
+ params: { gameId, itemId },
81629
+ url: new URL(c2.req.url),
81630
+ request: c2.req.raw
81631
+ };
81632
+ try {
81633
+ await deleteGameItem(ctx);
81634
+ return c2.body(null, 204);
81635
+ } catch (error2) {
81636
+ if (error2 instanceof ApiError) {
81637
+ return c2.json({ error: error2.message }, error2.statusCode);
81638
+ }
81639
+ console.error("Error in deleteGameItem:", error2);
81640
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
81641
+ return c2.json({ error: message2 }, 500);
81642
+ }
81643
+ });
81169
81644
  // src/routes/manifest.ts
81170
81645
  var manifestRouter = new Hono2;
81171
81646
  manifestRouter.get("/", async (c2) => {
@@ -81297,157 +81772,27 @@ shopRouter.get("/view", async (c2) => {
81297
81772
  return c2.json({ error: message2 }, 500);
81298
81773
  }
81299
81774
  });
81300
- // ../api-core/src/items/index.ts
81301
- async function listItems(ctx) {
81302
- const user = ctx.user;
81303
- if (!user) {
81304
- throw ApiError.unauthorized("Must be logged in to view items");
81305
- }
81306
- try {
81307
- const db = getDatabase();
81308
- const allItems = await db.query.items.findMany();
81309
- return allItems;
81310
- } catch (error2) {
81311
- if (error2 instanceof ApiError) {
81312
- throw error2;
81313
- }
81314
- logger2.error("Error fetching items:", error2);
81315
- throw ApiError.internal("Internal server error", error2);
81316
- }
81317
- }
81318
- async function getItemById(ctx) {
81319
- const user = ctx.user;
81320
- const itemId = ctx.params.itemId;
81321
- if (!user) {
81322
- throw ApiError.unauthorized("Must be logged in to view item details");
81323
- }
81324
- if (!itemId) {
81325
- throw ApiError.badRequest("Missing item ID");
81326
- }
81327
- try {
81328
- const db = getDatabase();
81329
- const item = await db.query.items.findFirst({
81330
- where: eq(items.id, itemId)
81331
- });
81332
- if (!item) {
81333
- throw ApiError.notFound("Item not found");
81334
- }
81335
- return item;
81336
- } catch (error2) {
81337
- if (error2 instanceof ApiError) {
81338
- throw error2;
81339
- }
81340
- logger2.error(`Error fetching item ${itemId}:`, error2);
81341
- throw ApiError.internal("Internal server error", error2);
81342
- }
81343
- }
81344
- async function createItem(ctx) {
81345
- const user = ctx.user;
81346
- if (!user || user.role !== "admin") {
81347
- throw ApiError.forbidden("Admin access required");
81348
- }
81349
- let inputData;
81350
- try {
81351
- const requestBody = await ctx.request.json();
81352
- const validationResult = InsertItemSchema.safeParse(requestBody);
81353
- if (!validationResult.success) {
81354
- throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
81355
- }
81356
- inputData = validationResult.data;
81357
- } catch (error2) {
81358
- if (error2 instanceof ApiError) {
81359
- throw error2;
81360
- }
81361
- logger2.error("Failed to parse request body or invalid JSON:", error2);
81362
- throw ApiError.badRequest("Invalid JSON body");
81363
- }
81364
- try {
81365
- const db = getDatabase();
81366
- const [newItem] = await db.insert(items).values(inputData).returning();
81367
- if (!newItem) {
81368
- throw ApiError.internal("Failed to create item in database");
81369
- }
81370
- return newItem;
81371
- } catch (error2) {
81372
- if (error2 instanceof Error) {
81373
- if (error2.message.includes("duplicate key value violates unique constraint")) {
81374
- throw ApiError.conflict("An item with this internal name already exists");
81375
- }
81376
- }
81377
- logger2.error("Error creating item:", error2);
81378
- throw ApiError.internal("Internal server error", error2);
81379
- }
81380
- }
81381
- async function updateItem(ctx) {
81382
- const user = ctx.user;
81383
- const itemId = ctx.params.itemId;
81384
- if (!user || user.role !== "admin") {
81385
- throw ApiError.forbidden("Admin access required");
81386
- }
81387
- if (!itemId) {
81388
- throw ApiError.badRequest("Missing item ID");
81389
- }
81390
- let inputData;
81391
- try {
81392
- const requestBody = await ctx.request.json();
81393
- const validationResult = UpdateItemSchema.safeParse(requestBody);
81394
- if (!validationResult.success) {
81395
- throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
81396
- }
81397
- inputData = validationResult.data;
81398
- } catch (error2) {
81399
- if (error2 instanceof ApiError) {
81400
- throw error2;
81401
- }
81402
- logger2.error("Failed to parse request body or invalid JSON:", error2);
81403
- throw ApiError.badRequest("Invalid JSON body");
81404
- }
81405
- if (Object.keys(inputData).length === 0) {
81406
- throw ApiError.badRequest("No update data provided");
81407
- }
81408
- try {
81409
- const db = getDatabase();
81410
- const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
81411
- if (!updatedItem) {
81412
- throw ApiError.notFound("Item not found for update");
81413
- }
81414
- return updatedItem;
81415
- } catch (error2) {
81416
- if (error2 instanceof Error) {
81417
- if (error2.message.includes("duplicate key value violates unique constraint")) {
81418
- throw ApiError.conflict("An item with this internal name already exists");
81419
- }
81420
- }
81421
- logger2.error(`Error updating item ${itemId}:`, error2);
81422
- throw ApiError.internal("Internal server error", error2);
81423
- }
81424
- }
81425
- async function deleteItem(ctx) {
81426
- const user = ctx.user;
81427
- const itemId = ctx.params.itemId;
81428
- if (!user || user.role !== "admin") {
81429
- throw ApiError.forbidden("Admin access required");
81430
- }
81431
- if (!itemId) {
81432
- throw ApiError.badRequest("Missing item ID");
81433
- }
81775
+ // src/routes/items.ts
81776
+ var itemsRouter = new Hono2;
81777
+ itemsRouter.get("/resolve", async (c2) => {
81778
+ const ctx = {
81779
+ user: c2.get("user"),
81780
+ params: {},
81781
+ url: new URL(c2.req.url),
81782
+ request: c2.req.raw
81783
+ };
81434
81784
  try {
81435
- const db = getDatabase();
81436
- const result = await db.delete(items).where(eq(items.id, itemId)).returning({ id: items.id });
81437
- if (result.length === 0) {
81438
- throw ApiError.notFound("Item not found for deletion");
81439
- }
81785
+ const result = await resolveItem(ctx);
81786
+ return c2.json(result);
81440
81787
  } catch (error2) {
81441
81788
  if (error2 instanceof ApiError) {
81442
- throw error2;
81789
+ return c2.json({ error: error2.message }, error2.statusCode);
81443
81790
  }
81444
- logger2.error(`Error deleting item ${itemId}:`, error2);
81445
- throw ApiError.internal("Internal server error", error2);
81791
+ console.error("Error in resolveItem:", error2);
81792
+ const message2 = error2 instanceof Error ? error2.message : "Internal server error";
81793
+ return c2.json({ error: message2 }, 500);
81446
81794
  }
81447
- }
81448
-
81449
- // src/routes/items.ts
81450
- var itemsRouter = new Hono2;
81795
+ });
81451
81796
  itemsRouter.post("/", async (c2) => {
81452
81797
  const ctx = {
81453
81798
  user: c2.get("user"),
@@ -81620,8 +81965,8 @@ async function createCurrency(ctx) {
81620
81965
  } catch (error2) {
81621
81966
  if (error2 instanceof Error) {
81622
81967
  if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
81623
- if (error2.message.includes("currencies_internal_name_unique")) {
81624
- throw ApiError.conflict("A currency with this internal name already exists");
81968
+ if (error2.message.includes("currencies_slug_unique")) {
81969
+ throw ApiError.conflict("A currency with this slug already exists");
81625
81970
  }
81626
81971
  throw ApiError.conflict("A similar currency already exists");
81627
81972
  }
@@ -81667,8 +82012,8 @@ async function updateCurrency(ctx) {
81667
82012
  } catch (error2) {
81668
82013
  if (error2 instanceof Error) {
81669
82014
  if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
81670
- if (error2.message.includes("currencies_internal_name_unique")) {
81671
- throw ApiError.conflict("A currency with this internal name already exists");
82015
+ if (error2.message.includes("currencies_slug_unique")) {
82016
+ throw ApiError.conflict("A currency with this slug already exists");
81672
82017
  }
81673
82018
  throw ApiError.conflict("A similar currency already exists");
81674
82019
  }