@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/cli.js
CHANGED
|
@@ -1707,8 +1707,8 @@ is not a problem with esbuild. You need to fix your environment instead.
|
|
|
1707
1707
|
if (isFirstPacket) {
|
|
1708
1708
|
isFirstPacket = false;
|
|
1709
1709
|
let binaryVersion = String.fromCharCode(...bytes);
|
|
1710
|
-
if (binaryVersion !== "0.25.
|
|
1711
|
-
throw new Error(`Cannot start service: Host version "${"0.25.
|
|
1710
|
+
if (binaryVersion !== "0.25.5") {
|
|
1711
|
+
throw new Error(`Cannot start service: Host version "${"0.25.5"}" does not match binary version ${quote(binaryVersion)}`);
|
|
1712
1712
|
}
|
|
1713
1713
|
return;
|
|
1714
1714
|
}
|
|
@@ -2896,7 +2896,7 @@ for your current platform.`);
|
|
|
2896
2896
|
} catch (e) {}
|
|
2897
2897
|
if (pnpapi) {
|
|
2898
2898
|
const root = pnpapi.getPackageInformation(pnpapi.topLevel).packageLocation;
|
|
2899
|
-
const binTargetPath = path.join(root, "node_modules", ".cache", "esbuild", `pnpapi-${pkg.replace("/", "-")}-${"0.25.
|
|
2899
|
+
const binTargetPath = path.join(root, "node_modules", ".cache", "esbuild", `pnpapi-${pkg.replace("/", "-")}-${"0.25.5"}-${path.basename(subpath)}`);
|
|
2900
2900
|
if (!fs3.existsSync(binTargetPath)) {
|
|
2901
2901
|
fs3.mkdirSync(path.dirname(binTargetPath), { recursive: true });
|
|
2902
2902
|
fs3.copyFileSync(binPath, binTargetPath);
|
|
@@ -2924,7 +2924,7 @@ for your current platform.`);
|
|
|
2924
2924
|
}
|
|
2925
2925
|
}
|
|
2926
2926
|
var _a;
|
|
2927
|
-
var isInternalWorkerThread = ((_a = worker_threads == null ? undefined : worker_threads.workerData) == null ? undefined : _a.esbuildVersion) === "0.25.
|
|
2927
|
+
var isInternalWorkerThread = ((_a = worker_threads == null ? undefined : worker_threads.workerData) == null ? undefined : _a.esbuildVersion) === "0.25.5";
|
|
2928
2928
|
var esbuildCommandAndArgs = () => {
|
|
2929
2929
|
if ((!ESBUILD_BINARY_PATH || false) && (path2.basename(__filename) !== "main.js" || path2.basename(__dirname) !== "lib")) {
|
|
2930
2930
|
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.
|
|
@@ -2986,7 +2986,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
2986
2986
|
}
|
|
2987
2987
|
}
|
|
2988
2988
|
};
|
|
2989
|
-
var version2 = "0.25.
|
|
2989
|
+
var version2 = "0.25.5";
|
|
2990
2990
|
var build = (options) => ensureServiceIsRunning().build(options);
|
|
2991
2991
|
var context = (buildOptions) => ensureServiceIsRunning().context(buildOptions);
|
|
2992
2992
|
var transform = (input, options) => ensureServiceIsRunning().transform(input, options);
|
|
@@ -3104,7 +3104,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
3104
3104
|
if (longLivedService)
|
|
3105
3105
|
return longLivedService;
|
|
3106
3106
|
let [command, args2] = esbuildCommandAndArgs();
|
|
3107
|
-
let child = child_process.spawn(command, args2.concat(`--service=${"0.25.
|
|
3107
|
+
let child = child_process.spawn(command, args2.concat(`--service=${"0.25.5"}`, "--ping"), {
|
|
3108
3108
|
windowsHide: true,
|
|
3109
3109
|
stdio: ["pipe", "pipe", "inherit"],
|
|
3110
3110
|
cwd: defaultWD
|
|
@@ -3212,7 +3212,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
3212
3212
|
esbuild: node_exports
|
|
3213
3213
|
});
|
|
3214
3214
|
callback(service);
|
|
3215
|
-
let stdout = child_process.execFileSync(command, args2.concat(`--service=${"0.25.
|
|
3215
|
+
let stdout = child_process.execFileSync(command, args2.concat(`--service=${"0.25.5"}`), {
|
|
3216
3216
|
cwd: defaultWD,
|
|
3217
3217
|
windowsHide: true,
|
|
3218
3218
|
input: stdin,
|
|
@@ -3228,7 +3228,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
3228
3228
|
var startWorkerThreadService = (worker_threads2) => {
|
|
3229
3229
|
let { port1: mainPort, port2: workerPort } = new worker_threads2.MessageChannel;
|
|
3230
3230
|
let worker = new worker_threads2.Worker(__filename, {
|
|
3231
|
-
workerData: { workerPort, defaultWD, esbuildVersion: "0.25.
|
|
3231
|
+
workerData: { workerPort, defaultWD, esbuildVersion: "0.25.5" },
|
|
3232
3232
|
transferList: [workerPort],
|
|
3233
3233
|
execArgv: []
|
|
3234
3234
|
});
|
|
@@ -52246,9 +52246,9 @@ import { Http2ServerRequest } from "http2";
|
|
|
52246
52246
|
import { Readable } from "stream";
|
|
52247
52247
|
import crypto2 from "crypto";
|
|
52248
52248
|
var RequestError = class extends Error {
|
|
52249
|
-
static name = "RequestError";
|
|
52250
52249
|
constructor(message, options) {
|
|
52251
52250
|
super(message, options);
|
|
52251
|
+
this.name = "RequestError";
|
|
52252
52252
|
}
|
|
52253
52253
|
};
|
|
52254
52254
|
var toRequestError = (e) => {
|
|
@@ -52853,7 +52853,8 @@ var PLAYCADEMY_CREDITS_ID = crypto.randomUUID();
|
|
|
52853
52853
|
var SAMPLE_ITEMS = [
|
|
52854
52854
|
{
|
|
52855
52855
|
id: PLAYCADEMY_CREDITS_ID,
|
|
52856
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
77746
|
+
version: "0.1.0-beta.7",
|
|
77726
77747
|
description: "Local development server for Playcademy game development",
|
|
77727
77748
|
type: "module",
|
|
77728
77749
|
exports: {
|
|
@@ -77735,18 +77756,18 @@ var package_default = {
|
|
|
77735
77756
|
types: "./dist/cli.js"
|
|
77736
77757
|
}
|
|
77737
77758
|
},
|
|
77738
|
-
files: [
|
|
77739
|
-
"dist"
|
|
77740
|
-
],
|
|
77741
77759
|
bin: {
|
|
77742
77760
|
"playcademy-sandbox": "./dist/cli.js"
|
|
77743
77761
|
},
|
|
77762
|
+
files: [
|
|
77763
|
+
"dist"
|
|
77764
|
+
],
|
|
77744
77765
|
scripts: {
|
|
77745
|
-
dev: "bun --watch src/cli.ts",
|
|
77746
|
-
start: "bun src/cli.ts",
|
|
77747
77766
|
build: "bun run build.ts",
|
|
77767
|
+
bump: 'bunx bumpp --no-tag --no-push -c "chore(@playcademy/sandbox): release v%s"',
|
|
77768
|
+
dev: "bun --watch src/cli.ts",
|
|
77748
77769
|
pub: "bun run build && bun run bump && bun publish --access public",
|
|
77749
|
-
|
|
77770
|
+
start: "bun src/cli.ts"
|
|
77750
77771
|
},
|
|
77751
77772
|
dependencies: {
|
|
77752
77773
|
"@electric-sql/pglite": "^0.3.2",
|
|
@@ -77761,7 +77782,8 @@ var package_default = {
|
|
|
77761
77782
|
devDependencies: {
|
|
77762
77783
|
"@playcademy/api-core": "workspace:*",
|
|
77763
77784
|
"@playcademy/data": "workspace:*",
|
|
77764
|
-
"@types/bun": "latest"
|
|
77785
|
+
"@types/bun": "latest",
|
|
77786
|
+
"yocto-spinner": "catalog:"
|
|
77765
77787
|
},
|
|
77766
77788
|
peerDependencies: {
|
|
77767
77789
|
typescript: "^5"
|
|
@@ -77826,7 +77848,7 @@ async function getUserMe(ctx) {
|
|
|
77826
77848
|
}
|
|
77827
77849
|
|
|
77828
77850
|
// ../data/src/constants.ts
|
|
77829
|
-
var
|
|
77851
|
+
var ITEM_SLUGS = {
|
|
77830
77852
|
PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
|
|
77831
77853
|
PLAYCADEMY_XP: "PLAYCADEMY_XP",
|
|
77832
77854
|
FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
|
|
@@ -77837,14 +77859,15 @@ var ITEM_INTERNAL_NAMES = {
|
|
|
77837
77859
|
SMALL_BACKPACK: "SMALL_BACKPACK"
|
|
77838
77860
|
};
|
|
77839
77861
|
var CURRENCIES = {
|
|
77840
|
-
PRIMARY:
|
|
77841
|
-
XP:
|
|
77862
|
+
PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
|
|
77863
|
+
XP: ITEM_SLUGS.PLAYCADEMY_XP
|
|
77842
77864
|
};
|
|
77843
77865
|
var BADGES = {
|
|
77844
|
-
FOUNDING_MEMBER:
|
|
77845
|
-
EARLY_ADOPTER:
|
|
77846
|
-
FIRST_GAME:
|
|
77866
|
+
FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
|
|
77867
|
+
EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
|
|
77868
|
+
FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
|
|
77847
77869
|
};
|
|
77870
|
+
var INTERACTION_TYPE = Object.fromEntries(interactionTypeEnum.enumValues.map((value) => [value, value]));
|
|
77848
77871
|
|
|
77849
77872
|
// ../api-core/src/utils/levels.ts
|
|
77850
77873
|
var levelConfigCache = null;
|
|
@@ -78001,7 +78024,7 @@ async function addXP(ctx, amount) {
|
|
|
78001
78024
|
creditsAwarded: creditsToAward
|
|
78002
78025
|
});
|
|
78003
78026
|
if (creditsToAward > 0) {
|
|
78004
|
-
const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.
|
|
78027
|
+
const [creditsItem] = await tx.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
|
|
78005
78028
|
if (!creditsItem) {
|
|
78006
78029
|
throw ApiError.internal(`${CURRENCIES.PRIMARY} item not found`);
|
|
78007
78030
|
}
|
|
@@ -78201,15 +78224,18 @@ async function getUserInventory(ctx) {
|
|
|
78201
78224
|
const db = getDatabase();
|
|
78202
78225
|
const inventory2 = await db.select({
|
|
78203
78226
|
id: inventoryItems.id,
|
|
78227
|
+
userId: inventoryItems.userId,
|
|
78204
78228
|
quantity: inventoryItems.quantity,
|
|
78205
78229
|
item: {
|
|
78206
78230
|
id: items.id,
|
|
78207
|
-
|
|
78231
|
+
slug: items.slug,
|
|
78232
|
+
gameId: items.gameId,
|
|
78208
78233
|
displayName: items.displayName,
|
|
78209
78234
|
description: items.description,
|
|
78210
78235
|
type: items.type,
|
|
78211
78236
|
imageUrl: items.imageUrl,
|
|
78212
|
-
metadata: items.metadata
|
|
78237
|
+
metadata: items.metadata,
|
|
78238
|
+
createdAt: items.createdAt
|
|
78213
78239
|
},
|
|
78214
78240
|
updatedAt: inventoryItems.updatedAt
|
|
78215
78241
|
}).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
|
|
@@ -79838,14 +79864,13 @@ async function listGames(ctx) {
|
|
|
79838
79864
|
if (!user) {
|
|
79839
79865
|
throw ApiError.unauthorized("Must be logged in to list games");
|
|
79840
79866
|
}
|
|
79841
|
-
if (user.role !== "admin" && user.role !== "developer") {
|
|
79842
|
-
throw ApiError.forbidden("Requires admin or developer privileges to list games");
|
|
79843
|
-
}
|
|
79844
79867
|
try {
|
|
79845
79868
|
const db = getDatabase();
|
|
79846
79869
|
let filter2 = undefined;
|
|
79847
79870
|
if (user.role === "developer") {
|
|
79848
79871
|
filter2 = eq(games.developerId, user.id);
|
|
79872
|
+
} else if (user.role === "player") {
|
|
79873
|
+
return [];
|
|
79849
79874
|
}
|
|
79850
79875
|
const games2 = await db.query.games.findMany({
|
|
79851
79876
|
where: filter2,
|
|
@@ -80086,6 +80111,375 @@ async function upsertGameBySlug(ctx) {
|
|
|
80086
80111
|
throw ApiError.internal("Internal server error", error2);
|
|
80087
80112
|
}
|
|
80088
80113
|
}
|
|
80114
|
+
|
|
80115
|
+
// ../api-core/src/items/index.ts
|
|
80116
|
+
async function validateGameOwnership(user, gameId) {
|
|
80117
|
+
if (user.role === "admin") {
|
|
80118
|
+
return;
|
|
80119
|
+
}
|
|
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");
|
|
80135
|
+
}
|
|
80136
|
+
} catch (error2) {
|
|
80137
|
+
if (error2 instanceof ApiError) {
|
|
80138
|
+
throw error2;
|
|
80139
|
+
}
|
|
80140
|
+
logger2.error(`Error checking game ownership for ${gameId}:`, error2);
|
|
80141
|
+
throw ApiError.internal("Internal server error", error2);
|
|
80142
|
+
}
|
|
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");
|
|
80148
|
+
}
|
|
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();
|
|
80160
|
+
}
|
|
80161
|
+
return allItems;
|
|
80162
|
+
} catch (error2) {
|
|
80163
|
+
if (error2 instanceof ApiError) {
|
|
80164
|
+
throw error2;
|
|
80165
|
+
}
|
|
80166
|
+
logger2.error("Error fetching items:", error2);
|
|
80167
|
+
throw ApiError.internal("Internal server error", error2);
|
|
80168
|
+
}
|
|
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");
|
|
80186
|
+
}
|
|
80187
|
+
return item;
|
|
80188
|
+
} catch (error2) {
|
|
80189
|
+
if (error2 instanceof ApiError) {
|
|
80190
|
+
throw error2;
|
|
80191
|
+
}
|
|
80192
|
+
logger2.error(`Error fetching item ${itemId}:`, error2);
|
|
80193
|
+
throw ApiError.internal("Internal server error", error2);
|
|
80194
|
+
}
|
|
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)}`);
|
|
80207
|
+
}
|
|
80208
|
+
inputData = validationResult.data;
|
|
80209
|
+
} catch (error2) {
|
|
80210
|
+
if (error2 instanceof ApiError) {
|
|
80211
|
+
throw error2;
|
|
80212
|
+
}
|
|
80213
|
+
logger2.error("Failed to parse request body or invalid JSON:", error2);
|
|
80214
|
+
throw ApiError.badRequest("Invalid JSON body");
|
|
80215
|
+
}
|
|
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");
|
|
80221
|
+
}
|
|
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
|
+
}
|
|
80229
|
+
}
|
|
80230
|
+
logger2.error("Error creating item:", error2);
|
|
80231
|
+
throw ApiError.internal("Internal server error", error2);
|
|
80232
|
+
}
|
|
80233
|
+
}
|
|
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");
|
|
80239
|
+
}
|
|
80240
|
+
if (!itemId) {
|
|
80241
|
+
throw ApiError.badRequest("Missing item ID");
|
|
80242
|
+
}
|
|
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)}`);
|
|
80249
|
+
}
|
|
80250
|
+
inputData = validationResult.data;
|
|
80251
|
+
} catch (error2) {
|
|
80252
|
+
if (error2 instanceof ApiError) {
|
|
80253
|
+
throw error2;
|
|
80254
|
+
}
|
|
80255
|
+
logger2.error("Failed to parse request body or invalid JSON:", error2);
|
|
80256
|
+
throw ApiError.badRequest("Invalid JSON body");
|
|
80257
|
+
}
|
|
80258
|
+
if (Object.keys(inputData).length === 0) {
|
|
80259
|
+
throw ApiError.badRequest("No update data provided");
|
|
80260
|
+
}
|
|
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");
|
|
80266
|
+
}
|
|
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
|
+
}
|
|
80273
|
+
}
|
|
80274
|
+
logger2.error(`Error updating item ${itemId}:`, error2);
|
|
80275
|
+
throw ApiError.internal("Internal server error", error2);
|
|
80276
|
+
}
|
|
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");
|
|
80283
|
+
}
|
|
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");
|
|
80292
|
+
}
|
|
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
|
+
}
|
|
80089
80483
|
// ../../node_modules/@oslojs/binary/dist/uint.js
|
|
80090
80484
|
class BigEndian {
|
|
80091
80485
|
uint8(data2, offset) {
|
|
@@ -81165,6 +81559,88 @@ gamesRouter.post("/uploads/finalize", async (c2) => {
|
|
|
81165
81559
|
return c2.json({ error: message2 }, 500);
|
|
81166
81560
|
}
|
|
81167
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
|
+
});
|
|
81168
81644
|
// src/routes/manifest.ts
|
|
81169
81645
|
var manifestRouter = new Hono2;
|
|
81170
81646
|
manifestRouter.get("/", async (c2) => {
|
|
@@ -81179,7 +81655,7 @@ manifestRouter.get("/", async (c2) => {
|
|
|
81179
81655
|
{ method: "GET", url: `${baseUrl}/api/users/me` },
|
|
81180
81656
|
{ method: "GET", url: `${baseUrl}/api/inventory` },
|
|
81181
81657
|
{ method: "POST", url: `${baseUrl}/api/inventory/add` },
|
|
81182
|
-
{ method: "POST", url: `${baseUrl}/api/inventory/
|
|
81658
|
+
{ method: "POST", url: `${baseUrl}/api/inventory/remove` },
|
|
81183
81659
|
{ method: "POST", url: `${baseUrl}/api/games/:gameId/sessions` },
|
|
81184
81660
|
{
|
|
81185
81661
|
method: "POST",
|
|
@@ -81296,157 +81772,27 @@ shopRouter.get("/view", async (c2) => {
|
|
|
81296
81772
|
return c2.json({ error: message2 }, 500);
|
|
81297
81773
|
}
|
|
81298
81774
|
});
|
|
81299
|
-
//
|
|
81300
|
-
|
|
81301
|
-
|
|
81302
|
-
|
|
81303
|
-
|
|
81304
|
-
|
|
81305
|
-
|
|
81306
|
-
|
|
81307
|
-
|
|
81308
|
-
return allItems;
|
|
81309
|
-
} catch (error2) {
|
|
81310
|
-
if (error2 instanceof ApiError) {
|
|
81311
|
-
throw error2;
|
|
81312
|
-
}
|
|
81313
|
-
logger2.error("Error fetching items:", error2);
|
|
81314
|
-
throw ApiError.internal("Internal server error", error2);
|
|
81315
|
-
}
|
|
81316
|
-
}
|
|
81317
|
-
async function getItemById(ctx) {
|
|
81318
|
-
const user = ctx.user;
|
|
81319
|
-
const itemId = ctx.params.itemId;
|
|
81320
|
-
if (!user) {
|
|
81321
|
-
throw ApiError.unauthorized("Must be logged in to view item details");
|
|
81322
|
-
}
|
|
81323
|
-
if (!itemId) {
|
|
81324
|
-
throw ApiError.badRequest("Missing item ID");
|
|
81325
|
-
}
|
|
81326
|
-
try {
|
|
81327
|
-
const db = getDatabase();
|
|
81328
|
-
const item = await db.query.items.findFirst({
|
|
81329
|
-
where: eq(items.id, itemId)
|
|
81330
|
-
});
|
|
81331
|
-
if (!item) {
|
|
81332
|
-
throw ApiError.notFound("Item not found");
|
|
81333
|
-
}
|
|
81334
|
-
return item;
|
|
81335
|
-
} catch (error2) {
|
|
81336
|
-
if (error2 instanceof ApiError) {
|
|
81337
|
-
throw error2;
|
|
81338
|
-
}
|
|
81339
|
-
logger2.error(`Error fetching item ${itemId}:`, error2);
|
|
81340
|
-
throw ApiError.internal("Internal server error", error2);
|
|
81341
|
-
}
|
|
81342
|
-
}
|
|
81343
|
-
async function createItem(ctx) {
|
|
81344
|
-
const user = ctx.user;
|
|
81345
|
-
if (!user || user.role !== "admin") {
|
|
81346
|
-
throw ApiError.forbidden("Admin access required");
|
|
81347
|
-
}
|
|
81348
|
-
let inputData;
|
|
81349
|
-
try {
|
|
81350
|
-
const requestBody = await ctx.request.json();
|
|
81351
|
-
const validationResult = InsertItemSchema.safeParse(requestBody);
|
|
81352
|
-
if (!validationResult.success) {
|
|
81353
|
-
throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
|
|
81354
|
-
}
|
|
81355
|
-
inputData = validationResult.data;
|
|
81356
|
-
} catch (error2) {
|
|
81357
|
-
if (error2 instanceof ApiError) {
|
|
81358
|
-
throw error2;
|
|
81359
|
-
}
|
|
81360
|
-
logger2.error("Failed to parse request body or invalid JSON:", error2);
|
|
81361
|
-
throw ApiError.badRequest("Invalid JSON body");
|
|
81362
|
-
}
|
|
81363
|
-
try {
|
|
81364
|
-
const db = getDatabase();
|
|
81365
|
-
const [newItem] = await db.insert(items).values(inputData).returning();
|
|
81366
|
-
if (!newItem) {
|
|
81367
|
-
throw ApiError.internal("Failed to create item in database");
|
|
81368
|
-
}
|
|
81369
|
-
return newItem;
|
|
81370
|
-
} catch (error2) {
|
|
81371
|
-
if (error2 instanceof Error) {
|
|
81372
|
-
if (error2.message.includes("duplicate key value violates unique constraint")) {
|
|
81373
|
-
throw ApiError.conflict("An item with this internal name already exists");
|
|
81374
|
-
}
|
|
81375
|
-
}
|
|
81376
|
-
logger2.error("Error creating item:", error2);
|
|
81377
|
-
throw ApiError.internal("Internal server error", error2);
|
|
81378
|
-
}
|
|
81379
|
-
}
|
|
81380
|
-
async function updateItem(ctx) {
|
|
81381
|
-
const user = ctx.user;
|
|
81382
|
-
const itemId = ctx.params.itemId;
|
|
81383
|
-
if (!user || user.role !== "admin") {
|
|
81384
|
-
throw ApiError.forbidden("Admin access required");
|
|
81385
|
-
}
|
|
81386
|
-
if (!itemId) {
|
|
81387
|
-
throw ApiError.badRequest("Missing item ID");
|
|
81388
|
-
}
|
|
81389
|
-
let inputData;
|
|
81390
|
-
try {
|
|
81391
|
-
const requestBody = await ctx.request.json();
|
|
81392
|
-
const validationResult = UpdateItemSchema.safeParse(requestBody);
|
|
81393
|
-
if (!validationResult.success) {
|
|
81394
|
-
throw ApiError.badRequest(`Validation failed: ${formatValidationErrors(validationResult.error)}`);
|
|
81395
|
-
}
|
|
81396
|
-
inputData = validationResult.data;
|
|
81397
|
-
} catch (error2) {
|
|
81398
|
-
if (error2 instanceof ApiError) {
|
|
81399
|
-
throw error2;
|
|
81400
|
-
}
|
|
81401
|
-
logger2.error("Failed to parse request body or invalid JSON:", error2);
|
|
81402
|
-
throw ApiError.badRequest("Invalid JSON body");
|
|
81403
|
-
}
|
|
81404
|
-
if (Object.keys(inputData).length === 0) {
|
|
81405
|
-
throw ApiError.badRequest("No update data provided");
|
|
81406
|
-
}
|
|
81407
|
-
try {
|
|
81408
|
-
const db = getDatabase();
|
|
81409
|
-
const [updatedItem] = await db.update(items).set(inputData).where(eq(items.id, itemId)).returning();
|
|
81410
|
-
if (!updatedItem) {
|
|
81411
|
-
throw ApiError.notFound("Item not found for update");
|
|
81412
|
-
}
|
|
81413
|
-
return updatedItem;
|
|
81414
|
-
} catch (error2) {
|
|
81415
|
-
if (error2 instanceof Error) {
|
|
81416
|
-
if (error2.message.includes("duplicate key value violates unique constraint")) {
|
|
81417
|
-
throw ApiError.conflict("An item with this internal name already exists");
|
|
81418
|
-
}
|
|
81419
|
-
}
|
|
81420
|
-
logger2.error(`Error updating item ${itemId}:`, error2);
|
|
81421
|
-
throw ApiError.internal("Internal server error", error2);
|
|
81422
|
-
}
|
|
81423
|
-
}
|
|
81424
|
-
async function deleteItem(ctx) {
|
|
81425
|
-
const user = ctx.user;
|
|
81426
|
-
const itemId = ctx.params.itemId;
|
|
81427
|
-
if (!user || user.role !== "admin") {
|
|
81428
|
-
throw ApiError.forbidden("Admin access required");
|
|
81429
|
-
}
|
|
81430
|
-
if (!itemId) {
|
|
81431
|
-
throw ApiError.badRequest("Missing item ID");
|
|
81432
|
-
}
|
|
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
|
+
};
|
|
81433
81784
|
try {
|
|
81434
|
-
const
|
|
81435
|
-
|
|
81436
|
-
if (result.length === 0) {
|
|
81437
|
-
throw ApiError.notFound("Item not found for deletion");
|
|
81438
|
-
}
|
|
81785
|
+
const result = await resolveItem(ctx);
|
|
81786
|
+
return c2.json(result);
|
|
81439
81787
|
} catch (error2) {
|
|
81440
81788
|
if (error2 instanceof ApiError) {
|
|
81441
|
-
|
|
81789
|
+
return c2.json({ error: error2.message }, error2.statusCode);
|
|
81442
81790
|
}
|
|
81443
|
-
|
|
81444
|
-
|
|
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);
|
|
81445
81794
|
}
|
|
81446
|
-
}
|
|
81447
|
-
|
|
81448
|
-
// src/routes/items.ts
|
|
81449
|
-
var itemsRouter = new Hono2;
|
|
81795
|
+
});
|
|
81450
81796
|
itemsRouter.post("/", async (c2) => {
|
|
81451
81797
|
const ctx = {
|
|
81452
81798
|
user: c2.get("user"),
|
|
@@ -81619,8 +81965,8 @@ async function createCurrency(ctx) {
|
|
|
81619
81965
|
} catch (error2) {
|
|
81620
81966
|
if (error2 instanceof Error) {
|
|
81621
81967
|
if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
|
|
81622
|
-
if (error2.message.includes("
|
|
81623
|
-
throw ApiError.conflict("A currency with this
|
|
81968
|
+
if (error2.message.includes("currencies_slug_unique")) {
|
|
81969
|
+
throw ApiError.conflict("A currency with this slug already exists");
|
|
81624
81970
|
}
|
|
81625
81971
|
throw ApiError.conflict("A similar currency already exists");
|
|
81626
81972
|
}
|
|
@@ -81666,8 +82012,8 @@ async function updateCurrency(ctx) {
|
|
|
81666
82012
|
} catch (error2) {
|
|
81667
82013
|
if (error2 instanceof Error) {
|
|
81668
82014
|
if (error2.message.includes("duplicate key value violates unique constraint") || error2.message.includes("UNIQUE constraint failed")) {
|
|
81669
|
-
if (error2.message.includes("
|
|
81670
|
-
throw ApiError.conflict("A currency with this
|
|
82015
|
+
if (error2.message.includes("currencies_slug_unique")) {
|
|
82016
|
+
throw ApiError.conflict("A currency with this slug already exists");
|
|
81671
82017
|
}
|
|
81672
82018
|
throw ApiError.conflict("A similar currency already exists");
|
|
81673
82019
|
}
|