@playcademy/sandbox 0.1.0-beta.6 → 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.
- package/dist/cli.js +539 -193
- package/dist/server.js +539 -193
- package/package.json +9 -8
package/dist/server.js
CHANGED
|
@@ -1706,8 +1706,8 @@ is not a problem with esbuild. You need to fix your environment instead.
|
|
|
1706
1706
|
if (isFirstPacket) {
|
|
1707
1707
|
isFirstPacket = false;
|
|
1708
1708
|
let binaryVersion = String.fromCharCode(...bytes);
|
|
1709
|
-
if (binaryVersion !== "0.25.
|
|
1710
|
-
throw new Error(`Cannot start service: Host version "${"0.25.
|
|
1709
|
+
if (binaryVersion !== "0.25.5") {
|
|
1710
|
+
throw new Error(`Cannot start service: Host version "${"0.25.5"}" does not match binary version ${quote(binaryVersion)}`);
|
|
1711
1711
|
}
|
|
1712
1712
|
return;
|
|
1713
1713
|
}
|
|
@@ -2895,7 +2895,7 @@ for your current platform.`);
|
|
|
2895
2895
|
} catch (e) {}
|
|
2896
2896
|
if (pnpapi) {
|
|
2897
2897
|
const root = pnpapi.getPackageInformation(pnpapi.topLevel).packageLocation;
|
|
2898
|
-
const binTargetPath = path.join(root, "node_modules", ".cache", "esbuild", `pnpapi-${pkg.replace("/", "-")}-${"0.25.
|
|
2898
|
+
const binTargetPath = path.join(root, "node_modules", ".cache", "esbuild", `pnpapi-${pkg.replace("/", "-")}-${"0.25.5"}-${path.basename(subpath)}`);
|
|
2899
2899
|
if (!fs3.existsSync(binTargetPath)) {
|
|
2900
2900
|
fs3.mkdirSync(path.dirname(binTargetPath), { recursive: true });
|
|
2901
2901
|
fs3.copyFileSync(binPath, binTargetPath);
|
|
@@ -2923,7 +2923,7 @@ for your current platform.`);
|
|
|
2923
2923
|
}
|
|
2924
2924
|
}
|
|
2925
2925
|
var _a;
|
|
2926
|
-
var isInternalWorkerThread = ((_a = worker_threads == null ? undefined : worker_threads.workerData) == null ? undefined : _a.esbuildVersion) === "0.25.
|
|
2926
|
+
var isInternalWorkerThread = ((_a = worker_threads == null ? undefined : worker_threads.workerData) == null ? undefined : _a.esbuildVersion) === "0.25.5";
|
|
2927
2927
|
var esbuildCommandAndArgs = () => {
|
|
2928
2928
|
if ((!ESBUILD_BINARY_PATH || false) && (path2.basename(__filename) !== "main.js" || path2.basename(__dirname) !== "lib")) {
|
|
2929
2929
|
throw new Error(`The esbuild JavaScript API cannot be bundled. Please mark the "esbuild" package as external so it's not included in the bundle.
|
|
@@ -2985,7 +2985,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
2985
2985
|
}
|
|
2986
2986
|
}
|
|
2987
2987
|
};
|
|
2988
|
-
var version2 = "0.25.
|
|
2988
|
+
var version2 = "0.25.5";
|
|
2989
2989
|
var build = (options) => ensureServiceIsRunning().build(options);
|
|
2990
2990
|
var context = (buildOptions) => ensureServiceIsRunning().context(buildOptions);
|
|
2991
2991
|
var transform = (input, options) => ensureServiceIsRunning().transform(input, options);
|
|
@@ -3103,7 +3103,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
3103
3103
|
if (longLivedService)
|
|
3104
3104
|
return longLivedService;
|
|
3105
3105
|
let [command, args2] = esbuildCommandAndArgs();
|
|
3106
|
-
let child = child_process.spawn(command, args2.concat(`--service=${"0.25.
|
|
3106
|
+
let child = child_process.spawn(command, args2.concat(`--service=${"0.25.5"}`, "--ping"), {
|
|
3107
3107
|
windowsHide: true,
|
|
3108
3108
|
stdio: ["pipe", "pipe", "inherit"],
|
|
3109
3109
|
cwd: defaultWD
|
|
@@ -3211,7 +3211,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
3211
3211
|
esbuild: node_exports
|
|
3212
3212
|
});
|
|
3213
3213
|
callback(service);
|
|
3214
|
-
let stdout = child_process.execFileSync(command, args2.concat(`--service=${"0.25.
|
|
3214
|
+
let stdout = child_process.execFileSync(command, args2.concat(`--service=${"0.25.5"}`), {
|
|
3215
3215
|
cwd: defaultWD,
|
|
3216
3216
|
windowsHide: true,
|
|
3217
3217
|
input: stdin,
|
|
@@ -3227,7 +3227,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
3227
3227
|
var startWorkerThreadService = (worker_threads2) => {
|
|
3228
3228
|
let { port1: mainPort, port2: workerPort } = new worker_threads2.MessageChannel;
|
|
3229
3229
|
let worker = new worker_threads2.Worker(__filename, {
|
|
3230
|
-
workerData: { workerPort, defaultWD, esbuildVersion: "0.25.
|
|
3230
|
+
workerData: { workerPort, defaultWD, esbuildVersion: "0.25.5" },
|
|
3231
3231
|
transferList: [workerPort],
|
|
3232
3232
|
execArgv: []
|
|
3233
3233
|
});
|
|
@@ -50336,9 +50336,9 @@ import { Http2ServerRequest } from "http2";
|
|
|
50336
50336
|
import { Readable } from "stream";
|
|
50337
50337
|
import crypto2 from "crypto";
|
|
50338
50338
|
var RequestError = class extends Error {
|
|
50339
|
-
static name = "RequestError";
|
|
50340
50339
|
constructor(message, options) {
|
|
50341
50340
|
super(message, options);
|
|
50341
|
+
this.name = "RequestError";
|
|
50342
50342
|
}
|
|
50343
50343
|
};
|
|
50344
50344
|
var toRequestError = (e) => {
|
|
@@ -50943,7 +50943,8 @@ var PLAYCADEMY_CREDITS_ID = crypto.randomUUID();
|
|
|
50943
50943
|
var SAMPLE_ITEMS = [
|
|
50944
50944
|
{
|
|
50945
50945
|
id: PLAYCADEMY_CREDITS_ID,
|
|
50946
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
75836
|
+
version: "0.1.0-beta.7",
|
|
75816
75837
|
description: "Local development server for Playcademy game development",
|
|
75817
75838
|
type: "module",
|
|
75818
75839
|
exports: {
|
|
@@ -75825,18 +75846,18 @@ var package_default = {
|
|
|
75825
75846
|
types: "./dist/cli.js"
|
|
75826
75847
|
}
|
|
75827
75848
|
},
|
|
75828
|
-
files: [
|
|
75829
|
-
"dist"
|
|
75830
|
-
],
|
|
75831
75849
|
bin: {
|
|
75832
75850
|
"playcademy-sandbox": "./dist/cli.js"
|
|
75833
75851
|
},
|
|
75852
|
+
files: [
|
|
75853
|
+
"dist"
|
|
75854
|
+
],
|
|
75834
75855
|
scripts: {
|
|
75835
|
-
dev: "bun --watch src/cli.ts",
|
|
75836
|
-
start: "bun src/cli.ts",
|
|
75837
75856
|
build: "bun run build.ts",
|
|
75857
|
+
bump: 'bunx bumpp --no-tag --no-push -c "chore(@playcademy/sandbox): release v%s"',
|
|
75858
|
+
dev: "bun --watch src/cli.ts",
|
|
75838
75859
|
pub: "bun run build && bun run bump && bun publish --access public",
|
|
75839
|
-
|
|
75860
|
+
start: "bun src/cli.ts"
|
|
75840
75861
|
},
|
|
75841
75862
|
dependencies: {
|
|
75842
75863
|
"@electric-sql/pglite": "^0.3.2",
|
|
@@ -75851,7 +75872,8 @@ var package_default = {
|
|
|
75851
75872
|
devDependencies: {
|
|
75852
75873
|
"@playcademy/api-core": "workspace:*",
|
|
75853
75874
|
"@playcademy/data": "workspace:*",
|
|
75854
|
-
"@types/bun": "latest"
|
|
75875
|
+
"@types/bun": "latest",
|
|
75876
|
+
"yocto-spinner": "catalog:"
|
|
75855
75877
|
},
|
|
75856
75878
|
peerDependencies: {
|
|
75857
75879
|
typescript: "^5"
|
|
@@ -75916,7 +75938,7 @@ async function getUserMe(ctx) {
|
|
|
75916
75938
|
}
|
|
75917
75939
|
|
|
75918
75940
|
// ../data/src/constants.ts
|
|
75919
|
-
var
|
|
75941
|
+
var ITEM_SLUGS = {
|
|
75920
75942
|
PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
|
|
75921
75943
|
PLAYCADEMY_XP: "PLAYCADEMY_XP",
|
|
75922
75944
|
FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
|
|
@@ -75927,14 +75949,15 @@ var ITEM_INTERNAL_NAMES = {
|
|
|
75927
75949
|
SMALL_BACKPACK: "SMALL_BACKPACK"
|
|
75928
75950
|
};
|
|
75929
75951
|
var CURRENCIES = {
|
|
75930
|
-
PRIMARY:
|
|
75931
|
-
XP:
|
|
75952
|
+
PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
|
|
75953
|
+
XP: ITEM_SLUGS.PLAYCADEMY_XP
|
|
75932
75954
|
};
|
|
75933
75955
|
var BADGES = {
|
|
75934
|
-
FOUNDING_MEMBER:
|
|
75935
|
-
EARLY_ADOPTER:
|
|
75936
|
-
FIRST_GAME:
|
|
75956
|
+
FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
|
|
75957
|
+
EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
|
|
75958
|
+
FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
|
|
75937
75959
|
};
|
|
75960
|
+
var INTERACTION_TYPE = Object.fromEntries(interactionTypeEnum.enumValues.map((value) => [value, value]));
|
|
75938
75961
|
|
|
75939
75962
|
// ../api-core/src/utils/levels.ts
|
|
75940
75963
|
var levelConfigCache = null;
|
|
@@ -76091,7 +76114,7 @@ async function addXP(ctx, amount) {
|
|
|
76091
76114
|
creditsAwarded: creditsToAward
|
|
76092
76115
|
});
|
|
76093
76116
|
if (creditsToAward > 0) {
|
|
76094
|
-
const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.
|
|
76117
|
+
const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
|
|
76095
76118
|
if (!creditsItem) {
|
|
76096
76119
|
throw ApiError.internal(`${CURRENCIES.PRIMARY} item not found`);
|
|
76097
76120
|
}
|
|
@@ -76291,15 +76314,18 @@ async function getUserInventory(ctx) {
|
|
|
76291
76314
|
const db = getDatabase();
|
|
76292
76315
|
const inventory2 = await db.select({
|
|
76293
76316
|
id: inventoryItems.id,
|
|
76317
|
+
userId: inventoryItems.userId,
|
|
76294
76318
|
quantity: inventoryItems.quantity,
|
|
76295
76319
|
item: {
|
|
76296
76320
|
id: items.id,
|
|
76297
|
-
|
|
76321
|
+
slug: items.slug,
|
|
76322
|
+
gameId: items.gameId,
|
|
76298
76323
|
displayName: items.displayName,
|
|
76299
76324
|
description: items.description,
|
|
76300
76325
|
type: items.type,
|
|
76301
76326
|
imageUrl: items.imageUrl,
|
|
76302
|
-
metadata: items.metadata
|
|
76327
|
+
metadata: items.metadata,
|
|
76328
|
+
createdAt: items.createdAt
|
|
76303
76329
|
},
|
|
76304
76330
|
updatedAt: inventoryItems.updatedAt
|
|
76305
76331
|
}).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
|
|
@@ -77928,14 +77954,13 @@ async function listGames(ctx) {
|
|
|
77928
77954
|
if (!user) {
|
|
77929
77955
|
throw ApiError.unauthorized("Must be logged in to list games");
|
|
77930
77956
|
}
|
|
77931
|
-
if (user.role !== "admin" && user.role !== "developer") {
|
|
77932
|
-
throw ApiError.forbidden("Requires admin or developer privileges to list games");
|
|
77933
|
-
}
|
|
77934
77957
|
try {
|
|
77935
77958
|
const db = getDatabase();
|
|
77936
77959
|
let filter2 = undefined;
|
|
77937
77960
|
if (user.role === "developer") {
|
|
77938
77961
|
filter2 = eq(games.developerId, user.id);
|
|
77962
|
+
} else if (user.role === "player") {
|
|
77963
|
+
return [];
|
|
77939
77964
|
}
|
|
77940
77965
|
const games2 = await db.query.games.findMany({
|
|
77941
77966
|
where: filter2,
|
|
@@ -78176,6 +78201,375 @@ async function upsertGameBySlug(ctx) {
|
|
|
78176
78201
|
throw ApiError.internal("Internal server error", error2);
|
|
78177
78202
|
}
|
|
78178
78203
|
}
|
|
78204
|
+
|
|
78205
|
+
// ../api-core/src/items/index.ts
|
|
78206
|
+
async function validateGameOwnership(user, gameId) {
|
|
78207
|
+
if (user.role === "admin") {
|
|
78208
|
+
return;
|
|
78209
|
+
}
|
|
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");
|
|
78225
|
+
}
|
|
78226
|
+
} catch (error2) {
|
|
78227
|
+
if (error2 instanceof ApiError) {
|
|
78228
|
+
throw error2;
|
|
78229
|
+
}
|
|
78230
|
+
logger2.error(`Error checking game ownership for ${gameId}:`, error2);
|
|
78231
|
+
throw ApiError.internal("Internal server error", error2);
|
|
78232
|
+
}
|
|
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");
|
|
78238
|
+
}
|
|
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();
|
|
78250
|
+
}
|
|
78251
|
+
return allItems;
|
|
78252
|
+
} catch (error2) {
|
|
78253
|
+
if (error2 instanceof ApiError) {
|
|
78254
|
+
throw error2;
|
|
78255
|
+
}
|
|
78256
|
+
logger2.error("Error fetching items:", error2);
|
|
78257
|
+
throw ApiError.internal("Internal server error", error2);
|
|
78258
|
+
}
|
|
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");
|
|
78276
|
+
}
|
|
78277
|
+
return item;
|
|
78278
|
+
} catch (error2) {
|
|
78279
|
+
if (error2 instanceof ApiError) {
|
|
78280
|
+
throw error2;
|
|
78281
|
+
}
|
|
78282
|
+
logger2.error(`Error fetching item ${itemId}:`, error2);
|
|
78283
|
+
throw ApiError.internal("Internal server error", error2);
|
|
78284
|
+
}
|
|
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)}`);
|
|
78297
|
+
}
|
|
78298
|
+
inputData = validationResult.data;
|
|
78299
|
+
} catch (error2) {
|
|
78300
|
+
if (error2 instanceof ApiError) {
|
|
78301
|
+
throw error2;
|
|
78302
|
+
}
|
|
78303
|
+
logger2.error("Failed to parse request body or invalid JSON:", error2);
|
|
78304
|
+
throw ApiError.badRequest("Invalid JSON body");
|
|
78305
|
+
}
|
|
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");
|
|
78311
|
+
}
|
|
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
|
+
}
|
|
78319
|
+
}
|
|
78320
|
+
logger2.error("Error creating item:", error2);
|
|
78321
|
+
throw ApiError.internal("Internal server error", error2);
|
|
78322
|
+
}
|
|
78323
|
+
}
|
|
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");
|
|
78329
|
+
}
|
|
78330
|
+
if (!itemId) {
|
|
78331
|
+
throw ApiError.badRequest("Missing item ID");
|
|
78332
|
+
}
|
|
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)}`);
|
|
78339
|
+
}
|
|
78340
|
+
inputData = validationResult.data;
|
|
78341
|
+
} catch (error2) {
|
|
78342
|
+
if (error2 instanceof ApiError) {
|
|
78343
|
+
throw error2;
|
|
78344
|
+
}
|
|
78345
|
+
logger2.error("Failed to parse request body or invalid JSON:", error2);
|
|
78346
|
+
throw ApiError.badRequest("Invalid JSON body");
|
|
78347
|
+
}
|
|
78348
|
+
if (Object.keys(inputData).length === 0) {
|
|
78349
|
+
throw ApiError.badRequest("No update data provided");
|
|
78350
|
+
}
|
|
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");
|
|
78356
|
+
}
|
|
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
|
+
}
|
|
78363
|
+
}
|
|
78364
|
+
logger2.error(`Error updating item ${itemId}:`, error2);
|
|
78365
|
+
throw ApiError.internal("Internal server error", error2);
|
|
78366
|
+
}
|
|
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");
|
|
78373
|
+
}
|
|
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");
|
|
78382
|
+
}
|
|
78383
|
+
} catch (error2) {
|
|
78384
|
+
if (error2 instanceof ApiError) {
|
|
78385
|
+
throw error2;
|
|
78386
|
+
}
|
|
78387
|
+
logger2.error(`Error deleting item ${itemId}:`, error2);
|
|
78388
|
+
throw ApiError.internal("Internal server error", error2);
|
|
78389
|
+
}
|
|
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
|
+
}
|
|
78179
78573
|
// ../../node_modules/@oslojs/binary/dist/uint.js
|
|
78180
78574
|
class BigEndian {
|
|
78181
78575
|
uint8(data2, offset) {
|
|
@@ -79255,6 +79649,88 @@ gamesRouter.post("/uploads/finalize", async (c2) => {
|
|
|
79255
79649
|
return c2.json({ error: message2 }, 500);
|
|
79256
79650
|
}
|
|
79257
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
|
+
});
|
|
79258
79734
|
// src/routes/manifest.ts
|
|
79259
79735
|
var manifestRouter = new Hono2;
|
|
79260
79736
|
manifestRouter.get("/", async (c2) => {
|
|
@@ -79269,7 +79745,7 @@ manifestRouter.get("/", async (c2) => {
|
|
|
79269
79745
|
{ method: "GET", url: `${baseUrl}/api/users/me` },
|
|
79270
79746
|
{ method: "GET", url: `${baseUrl}/api/inventory` },
|
|
79271
79747
|
{ method: "POST", url: `${baseUrl}/api/inventory/add` },
|
|
79272
|
-
{ method: "POST", url: `${baseUrl}/api/inventory/
|
|
79748
|
+
{ method: "POST", url: `${baseUrl}/api/inventory/remove` },
|
|
79273
79749
|
{ method: "POST", url: `${baseUrl}/api/games/:gameId/sessions` },
|
|
79274
79750
|
{
|
|
79275
79751
|
method: "POST",
|
|
@@ -79386,157 +79862,27 @@ shopRouter.get("/view", async (c2) => {
|
|
|
79386
79862
|
return c2.json({ error: message2 }, 500);
|
|
79387
79863
|
}
|
|
79388
79864
|
});
|
|
79389
|
-
//
|
|
79390
|
-
|
|
79391
|
-
|
|
79392
|
-
|
|
79393
|
-
|
|
79394
|
-
|
|
79395
|
-
|
|
79396
|
-
|
|
79397
|
-
|
|
79398
|
-
return allItems;
|
|
79399
|
-
} catch (error2) {
|
|
79400
|
-
if (error2 instanceof ApiError) {
|
|
79401
|
-
throw error2;
|
|
79402
|
-
}
|
|
79403
|
-
logger2.error("Error fetching items:", error2);
|
|
79404
|
-
throw ApiError.internal("Internal server error", error2);
|
|
79405
|
-
}
|
|
79406
|
-
}
|
|
79407
|
-
async function getItemById(ctx) {
|
|
79408
|
-
const user = ctx.user;
|
|
79409
|
-
const itemId = ctx.params.itemId;
|
|
79410
|
-
if (!user) {
|
|
79411
|
-
throw ApiError.unauthorized("Must be logged in to view item details");
|
|
79412
|
-
}
|
|
79413
|
-
if (!itemId) {
|
|
79414
|
-
throw ApiError.badRequest("Missing item ID");
|
|
79415
|
-
}
|
|
79416
|
-
try {
|
|
79417
|
-
const db = getDatabase();
|
|
79418
|
-
const item = await db.query.items.findFirst({
|
|
79419
|
-
where: eq(items.id, itemId)
|
|
79420
|
-
});
|
|
79421
|
-
if (!item) {
|
|
79422
|
-
throw ApiError.notFound("Item not found");
|
|
79423
|
-
}
|
|
79424
|
-
return item;
|
|
79425
|
-
} catch (error2) {
|
|
79426
|
-
if (error2 instanceof ApiError) {
|
|
79427
|
-
throw error2;
|
|
79428
|
-
}
|
|
79429
|
-
logger2.error(`Error fetching item ${itemId}:`, error2);
|
|
79430
|
-
throw ApiError.internal("Internal server error", error2);
|
|
79431
|
-
}
|
|
79432
|
-
}
|
|
79433
|
-
async function createItem(ctx) {
|
|
79434
|
-
const user = ctx.user;
|
|
79435
|
-
if (!user || user.role !== "admin") {
|
|
79436
|
-
throw ApiError.forbidden("Admin access required");
|
|
79437
|
-
}
|
|
79438
|
-
let inputData;
|
|
79439
|
-
try {
|
|
79440
|
-
const requestBody = await ctx.request.json();
|
|
79441
|
-
const validationResult = InsertItemSchema.safeParse(requestBody);
|
|
79442
|
-
if (!validationResult.success) {
|
|
79443
|
-
throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
|
|
79444
|
-
}
|
|
79445
|
-
inputData = validationResult.data;
|
|
79446
|
-
} catch (error2) {
|
|
79447
|
-
if (error2 instanceof ApiError) {
|
|
79448
|
-
throw error2;
|
|
79449
|
-
}
|
|
79450
|
-
logger2.error("Failed to parse request body or invalid JSON:", error2);
|
|
79451
|
-
throw ApiError.badRequest("Invalid JSON body");
|
|
79452
|
-
}
|
|
79453
|
-
try {
|
|
79454
|
-
const db = getDatabase();
|
|
79455
|
-
const [newItem] = await db.insert(items).values(inputData).returning();
|
|
79456
|
-
if (!newItem) {
|
|
79457
|
-
throw ApiError.internal("Failed to create item in database");
|
|
79458
|
-
}
|
|
79459
|
-
return newItem;
|
|
79460
|
-
} catch (error2) {
|
|
79461
|
-
if (error2 instanceof Error) {
|
|
79462
|
-
if (error2.message.includes("duplicate key value violates unique constraint")) {
|
|
79463
|
-
throw ApiError.conflict("An item with this internal name already exists");
|
|
79464
|
-
}
|
|
79465
|
-
}
|
|
79466
|
-
logger2.error("Error creating item:", error2);
|
|
79467
|
-
throw ApiError.internal("Internal server error", error2);
|
|
79468
|
-
}
|
|
79469
|
-
}
|
|
79470
|
-
async function updateItem(ctx) {
|
|
79471
|
-
const user = ctx.user;
|
|
79472
|
-
const itemId = ctx.params.itemId;
|
|
79473
|
-
if (!user || user.role !== "admin") {
|
|
79474
|
-
throw ApiError.forbidden("Admin access required");
|
|
79475
|
-
}
|
|
79476
|
-
if (!itemId) {
|
|
79477
|
-
throw ApiError.badRequest("Missing item ID");
|
|
79478
|
-
}
|
|
79479
|
-
let inputData;
|
|
79480
|
-
try {
|
|
79481
|
-
const requestBody = await ctx.request.json();
|
|
79482
|
-
const validationResult = UpdateItemSchema.safeParse(requestBody);
|
|
79483
|
-
if (!validationResult.success) {
|
|
79484
|
-
throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
|
|
79485
|
-
}
|
|
79486
|
-
inputData = validationResult.data;
|
|
79487
|
-
} catch (error2) {
|
|
79488
|
-
if (error2 instanceof ApiError) {
|
|
79489
|
-
throw error2;
|
|
79490
|
-
}
|
|
79491
|
-
logger2.error("Failed to parse request body or invalid JSON:", error2);
|
|
79492
|
-
throw ApiError.badRequest("Invalid JSON body");
|
|
79493
|
-
}
|
|
79494
|
-
if (Object.keys(inputData).length === 0) {
|
|
79495
|
-
throw ApiError.badRequest("No update data provided");
|
|
79496
|
-
}
|
|
79497
|
-
try {
|
|
79498
|
-
const db = getDatabase();
|
|
79499
|
-
const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
|
|
79500
|
-
if (!updatedItem) {
|
|
79501
|
-
throw ApiError.notFound("Item not found for update");
|
|
79502
|
-
}
|
|
79503
|
-
return updatedItem;
|
|
79504
|
-
} catch (error2) {
|
|
79505
|
-
if (error2 instanceof Error) {
|
|
79506
|
-
if (error2.message.includes("duplicate key value violates unique constraint")) {
|
|
79507
|
-
throw ApiError.conflict("An item with this internal name already exists");
|
|
79508
|
-
}
|
|
79509
|
-
}
|
|
79510
|
-
logger2.error(`Error updating item ${itemId}:`, error2);
|
|
79511
|
-
throw ApiError.internal("Internal server error", error2);
|
|
79512
|
-
}
|
|
79513
|
-
}
|
|
79514
|
-
async function deleteItem(ctx) {
|
|
79515
|
-
const user = ctx.user;
|
|
79516
|
-
const itemId = ctx.params.itemId;
|
|
79517
|
-
if (!user || user.role !== "admin") {
|
|
79518
|
-
throw ApiError.forbidden("Admin access required");
|
|
79519
|
-
}
|
|
79520
|
-
if (!itemId) {
|
|
79521
|
-
throw ApiError.badRequest("Missing item ID");
|
|
79522
|
-
}
|
|
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
|
+
};
|
|
79523
79874
|
try {
|
|
79524
|
-
const
|
|
79525
|
-
|
|
79526
|
-
if (result.length === 0) {
|
|
79527
|
-
throw ApiError.notFound("Item not found for deletion");
|
|
79528
|
-
}
|
|
79875
|
+
const result = await resolveItem(ctx);
|
|
79876
|
+
return c2.json(result);
|
|
79529
79877
|
} catch (error2) {
|
|
79530
79878
|
if (error2 instanceof ApiError) {
|
|
79531
|
-
|
|
79879
|
+
return c2.json({ error: error2.message }, error2.statusCode);
|
|
79532
79880
|
}
|
|
79533
|
-
|
|
79534
|
-
|
|
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);
|
|
79535
79884
|
}
|
|
79536
|
-
}
|
|
79537
|
-
|
|
79538
|
-
// src/routes/items.ts
|
|
79539
|
-
var itemsRouter = new Hono2;
|
|
79885
|
+
});
|
|
79540
79886
|
itemsRouter.post("/", async (c2) => {
|
|
79541
79887
|
const ctx = {
|
|
79542
79888
|
user: c2.get("user"),
|
|
@@ -79709,8 +80055,8 @@ async function createCurrency(ctx) {
|
|
|
79709
80055
|
} catch (error2) {
|
|
79710
80056
|
if (error2 instanceof Error) {
|
|
79711
80057
|
if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
|
|
79712
|
-
if (error2.message.includes("
|
|
79713
|
-
throw ApiError.conflict("A currency with this
|
|
80058
|
+
if (error2.message.includes("currencies_slug_unique")) {
|
|
80059
|
+
throw ApiError.conflict("A currency with this slug already exists");
|
|
79714
80060
|
}
|
|
79715
80061
|
throw ApiError.conflict("A similar currency already exists");
|
|
79716
80062
|
}
|
|
@@ -79756,8 +80102,8 @@ async function updateCurrency(ctx) {
|
|
|
79756
80102
|
} catch (error2) {
|
|
79757
80103
|
if (error2 instanceof Error) {
|
|
79758
80104
|
if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
|
|
79759
|
-
if (error2.message.includes("
|
|
79760
|
-
throw ApiError.conflict("A currency with this
|
|
80105
|
+
if (error2.message.includes("currencies_slug_unique")) {
|
|
80106
|
+
throw ApiError.conflict("A currency with this slug already exists");
|
|
79761
80107
|
}
|
|
79762
80108
|
throw ApiError.conflict("A similar currency already exists");
|
|
79763
80109
|
}
|