@playcademy/sdk 0.0.1-beta.24 → 0.0.1-beta.26

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/index.js CHANGED
@@ -10,6 +10,86 @@ var __export = (target, all) => {
10
10
  };
11
11
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
12
12
 
13
+ // ../logger/src/index.ts
14
+ var isBrowser = () => {
15
+ return typeof window !== "undefined" && typeof document !== "undefined";
16
+ }, colors, getLevelColor = (level) => {
17
+ switch (level) {
18
+ case "debug":
19
+ return colors.blue;
20
+ case "info":
21
+ return colors.cyan;
22
+ case "warn":
23
+ return colors.yellow;
24
+ case "error":
25
+ return colors.red;
26
+ default:
27
+ return colors.reset;
28
+ }
29
+ }, logInBrowser = (level, message, context) => {
30
+ const timestamp = new Date().toISOString();
31
+ const levelUpper = level.toUpperCase();
32
+ const consoleMethod = getConsoleMethod(level);
33
+ if (context && Object.keys(context).length > 0) {
34
+ consoleMethod(`[${timestamp}] ${levelUpper}`, message, context);
35
+ } else {
36
+ consoleMethod(`[${timestamp}] ${levelUpper}`, message);
37
+ }
38
+ }, logOnServer = (level, message, context) => {
39
+ const consoleMethod = getConsoleMethod(level);
40
+ if (true) {
41
+ const timestamp = new Date().toISOString();
42
+ const levelColor = getLevelColor(level);
43
+ const levelUpper = level.toUpperCase().padEnd(5);
44
+ const coloredPrefix = `${colors.dim}[${timestamp}]${colors.reset} ${levelColor}${levelUpper}${colors.reset}`;
45
+ if (context && Object.keys(context).length > 0) {
46
+ consoleMethod(`${coloredPrefix} ${message}`, context);
47
+ } else {
48
+ consoleMethod(`${coloredPrefix} ${message}`);
49
+ }
50
+ } else {}
51
+ }, getConsoleMethod = (level) => {
52
+ switch (level) {
53
+ case "debug":
54
+ return console.debug;
55
+ case "info":
56
+ return console.info;
57
+ case "warn":
58
+ return console.warn;
59
+ case "error":
60
+ return console.error;
61
+ default:
62
+ return console.log;
63
+ }
64
+ }, performLog = (level, message, context) => {
65
+ if (level === "debug" && false) {}
66
+ if (isBrowser()) {
67
+ logInBrowser(level, message, context);
68
+ } else {
69
+ logOnServer(level, message, context);
70
+ }
71
+ }, createLogger = () => {
72
+ return {
73
+ debug: (message, context) => performLog("debug", message, context),
74
+ info: (message, context) => performLog("info", message, context),
75
+ warn: (message, context) => performLog("warn", message, context),
76
+ error: (message, context) => performLog("error", message, context),
77
+ log: performLog
78
+ };
79
+ }, log;
80
+ var init_src = __esm(() => {
81
+ colors = {
82
+ reset: "\x1B[0m",
83
+ dim: "\x1B[2m",
84
+ red: "\x1B[31m",
85
+ yellow: "\x1B[33m",
86
+ blue: "\x1B[34m",
87
+ cyan: "\x1B[36m",
88
+ gray: "\x1B[90m"
89
+ };
90
+ log = createLogger();
91
+ });
92
+
13
93
  // src/core/errors.ts
14
94
  var PlaycademyError, ApiError;
15
95
  var init_errors = __esm(() => {
@@ -31,68 +111,6 @@ var init_errors = __esm(() => {
31
111
  };
32
112
  });
33
113
 
34
- // src/core/request.ts
35
- async function request({
36
- path,
37
- baseUrl,
38
- token,
39
- method = "GET",
40
- body,
41
- extraHeaders = {}
42
- }) {
43
- const url = baseUrl.replace(/\/$/, "") + (path.startsWith("/") ? path : `/${path}`);
44
- const headers = { ...extraHeaders };
45
- let payload;
46
- if (body instanceof FormData) {
47
- payload = body;
48
- } else if (body !== undefined && body !== null) {
49
- payload = JSON.stringify(body);
50
- headers["Content-Type"] = "application/json";
51
- }
52
- if (token)
53
- headers["Authorization"] = `Bearer ${token}`;
54
- const res = await fetch(url, {
55
- method,
56
- headers,
57
- body: payload,
58
- credentials: "omit"
59
- });
60
- if (!res.ok) {
61
- const errorBody = await res.clone().json().catch(() => res.text().catch(() => {
62
- return;
63
- })) ?? undefined;
64
- throw new ApiError(res.status, res.statusText, errorBody);
65
- }
66
- if (res.status === 204)
67
- return;
68
- const contentType = res.headers.get("content-type") ?? "";
69
- if (contentType.includes("application/json")) {
70
- return await res.json();
71
- }
72
- return await res.text();
73
- }
74
- async function fetchManifest(assetBundleBase) {
75
- const manifestUrl = `${assetBundleBase.replace(/\/$/, "")}/playcademy.manifest.json`;
76
- try {
77
- const response = await fetch(manifestUrl);
78
- if (!response.ok) {
79
- console.error(`[fetchManifest] Failed to fetch manifest from ${manifestUrl}. Status: ${response.status}`);
80
- throw new PlaycademyError(`Failed to fetch manifest: ${response.status} ${response.statusText}`);
81
- }
82
- return await response.json();
83
- } catch (error) {
84
- if (error instanceof PlaycademyError) {
85
- throw error;
86
- }
87
- console.error(`[fetchManifest] Error fetching or parsing manifest from ${manifestUrl}:`, error);
88
- throw new PlaycademyError("Failed to load or parse game manifest");
89
- }
90
- }
91
- var init_request = __esm(() => {
92
- init_errors();
93
- init_errors();
94
- });
95
-
96
114
  // src/core/namespaces/auth.ts
97
115
  function createAuthNamespace(client) {
98
116
  return {
@@ -208,7 +226,10 @@ function createRuntimeNamespace(client) {
208
226
  try {
209
227
  await client.games.endSession(client["internalClientSessionId"], client["gameId"]);
210
228
  } catch (error) {
211
- console.error("[SDK] Failed to auto-end session:", client["internalClientSessionId"], error);
229
+ log.error("[Playcademy SDK] Failed to auto-end session:", {
230
+ sessionId: client["internalClientSessionId"],
231
+ error
232
+ });
212
233
  }
213
234
  }
214
235
  messaging.send("PLAYCADEMY_EXIT" /* EXIT */, undefined);
@@ -216,9 +237,74 @@ function createRuntimeNamespace(client) {
216
237
  };
217
238
  }
218
239
  var init_runtime = __esm(() => {
240
+ init_src();
219
241
  init_messaging();
220
242
  });
221
243
 
244
+ // src/core/request.ts
245
+ async function request({
246
+ path,
247
+ baseUrl,
248
+ token,
249
+ method = "GET",
250
+ body,
251
+ extraHeaders = {}
252
+ }) {
253
+ const url = baseUrl.replace(/\/$/, "") + (path.startsWith("/") ? path : `/${path}`);
254
+ const headers = { ...extraHeaders };
255
+ let payload;
256
+ if (body instanceof FormData) {
257
+ payload = body;
258
+ } else if (body !== undefined && body !== null) {
259
+ payload = JSON.stringify(body);
260
+ headers["Content-Type"] = "application/json";
261
+ }
262
+ if (token)
263
+ headers["Authorization"] = `Bearer ${token}`;
264
+ const res = await fetch(url, {
265
+ method,
266
+ headers,
267
+ body: payload,
268
+ credentials: "omit"
269
+ });
270
+ if (!res.ok) {
271
+ const errorBody = await res.clone().json().catch(() => res.text().catch(() => {
272
+ return;
273
+ })) ?? undefined;
274
+ throw new ApiError(res.status, res.statusText, errorBody);
275
+ }
276
+ if (res.status === 204)
277
+ return;
278
+ const contentType = res.headers.get("content-type") ?? "";
279
+ if (contentType.includes("application/json")) {
280
+ return await res.json();
281
+ }
282
+ return await res.text();
283
+ }
284
+ async function fetchManifest(assetBundleBase) {
285
+ const manifestUrl = `${assetBundleBase.replace(/\/$/, "")}/playcademy.manifest.json`;
286
+ try {
287
+ const response = await fetch(manifestUrl);
288
+ if (!response.ok) {
289
+ log.error(`[fetchManifest] Failed to fetch manifest from ${manifestUrl}. Status: ${response.status}`);
290
+ throw new PlaycademyError(`Failed to fetch manifest: ${response.status} ${response.statusText}`);
291
+ }
292
+ return await response.json();
293
+ } catch (error) {
294
+ if (error instanceof PlaycademyError) {
295
+ throw error;
296
+ }
297
+ log.error(`[Playcademy SDK] Error fetching or parsing manifest from ${manifestUrl}:`, {
298
+ error
299
+ });
300
+ throw new PlaycademyError("Failed to load or parse game manifest");
301
+ }
302
+ }
303
+ var init_request = __esm(() => {
304
+ init_src();
305
+ init_errors();
306
+ });
307
+
222
308
  // src/core/namespaces/games.ts
223
309
  function createGamesNamespace(client) {
224
310
  return {
@@ -263,15 +349,17 @@ function createUsersNamespace(client) {
263
349
  const resolveItemId = async (identifier) => {
264
350
  if (UUID_REGEX.test(identifier))
265
351
  return identifier;
266
- if (itemIdCache.has(identifier))
267
- return itemIdCache.get(identifier);
268
- const inventory = await client.users.inventory.get();
269
- const item = inventory.find((inv) => inv.item?.internalName === identifier);
270
- if (!item) {
271
- throw new Error(`Item with internal name '${identifier}' not found in inventory`);
272
- }
273
- itemIdCache.set(identifier, item.item.id);
274
- return item.item.id;
352
+ const gameId = client["gameId"];
353
+ const cacheKey = gameId ? `${identifier}:${gameId}` : identifier;
354
+ if (itemIdCache.has(cacheKey)) {
355
+ return itemIdCache.get(cacheKey);
356
+ }
357
+ const queryParams = new URLSearchParams({ slug: identifier });
358
+ if (gameId)
359
+ queryParams.append("gameId", gameId);
360
+ const item = await client["request"](`/items/resolve?${queryParams.toString()}`, "GET");
361
+ itemIdCache.set(cacheKey, item.id);
362
+ return item.id;
275
363
  };
276
364
  return {
277
365
  me: async () => {
@@ -300,12 +388,9 @@ function createUsersNamespace(client) {
300
388
  return res;
301
389
  },
302
390
  quantity: async (identifier) => {
391
+ const itemId = await resolveItemId(identifier);
303
392
  const inventory = await client.users.inventory.get();
304
- if (UUID_REGEX.test(identifier)) {
305
- const item2 = inventory.find((inv) => inv.item?.id === identifier);
306
- return item2?.quantity ?? 0;
307
- }
308
- const item = inventory.find((inv) => inv.item?.internalName === identifier);
393
+ const item = inventory.find((inv) => inv.item?.id === itemId);
309
394
  return item?.quantity ?? 0;
310
395
  },
311
396
  has: async (identifier, minQuantity = 1) => {
@@ -337,9 +422,39 @@ function createDevNamespace(client) {
337
422
  delete: (gameId) => client["request"](`/games/${gameId}`, "DELETE")
338
423
  },
339
424
  keys: {
340
- createKey: (gameId, label) => client["request"](`/dev/games/${gameId}/keys`, "POST", { label }),
341
- listKeys: (gameId) => client["request"](`/dev/games/${gameId}/keys`, "GET"),
425
+ createKey: (label) => client["request"](`/dev/keys`, "POST", { label }),
426
+ listKeys: () => client["request"](`/dev/keys`, "GET"),
342
427
  revokeKey: (keyId) => client["request"](`/dev/keys/${keyId}`, "DELETE")
428
+ },
429
+ items: {
430
+ create: (gameId, slug, itemData) => client["request"](`/games/${gameId}/items`, "POST", {
431
+ slug,
432
+ ...itemData
433
+ }),
434
+ update: (gameId, itemId, updates) => client["request"](`/games/${gameId}/items/${itemId}`, "PATCH", updates),
435
+ list: (gameId) => client["request"](`/games/${gameId}/items`, "GET"),
436
+ get: (gameId, slug) => {
437
+ const queryParams = new URLSearchParams({ slug, gameId });
438
+ return client["request"](`/items/resolve?${queryParams.toString()}`, "GET");
439
+ },
440
+ delete: (gameId, itemId) => client["request"](`/games/${gameId}/items/${itemId}`, "DELETE"),
441
+ shop: {
442
+ create: (gameId, itemId, listingData) => {
443
+ return client["request"](`/games/${gameId}/items/${itemId}/shop-listing`, "POST", listingData);
444
+ },
445
+ get: (gameId, itemId) => {
446
+ return client["request"](`/games/${gameId}/items/${itemId}/shop-listing`, "GET");
447
+ },
448
+ update: (gameId, itemId, updates) => {
449
+ return client["request"](`/games/${gameId}/items/${itemId}/shop-listing`, "PATCH", updates);
450
+ },
451
+ delete: (gameId, itemId) => {
452
+ return client["request"](`/games/${gameId}/items/${itemId}/shop-listing`, "DELETE");
453
+ },
454
+ list: (gameId) => {
455
+ return client["request"](`/games/${gameId}/shop-listings`, "GET");
456
+ }
457
+ }
343
458
  }
344
459
  };
345
460
  }
@@ -437,10 +552,365 @@ function createLevelsNamespace(client) {
437
552
  };
438
553
  }
439
554
 
555
+ // ../data/src/domains/user/table.ts
556
+ import { boolean, pgEnum, pgTable, text, timestamp, uniqueIndex } from "drizzle-orm/pg-core";
557
+ var userRoleEnum, developerStatusEnum, users, accounts, sessions, verification;
558
+ var init_table = __esm(() => {
559
+ userRoleEnum = pgEnum("user_role", ["admin", "player", "developer"]);
560
+ developerStatusEnum = pgEnum("developer_status", ["none", "pending", "approved"]);
561
+ users = pgTable("user", {
562
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
563
+ name: text("name").notNull(),
564
+ username: text("username").unique(),
565
+ email: text("email").notNull().unique(),
566
+ emailVerified: boolean("email_verified").notNull().default(false),
567
+ image: text("image"),
568
+ role: userRoleEnum("role").notNull().default("player"),
569
+ developerStatus: developerStatusEnum("developer_status").notNull().default("none"),
570
+ createdAt: timestamp("created_at", {
571
+ mode: "date",
572
+ withTimezone: true
573
+ }).notNull(),
574
+ updatedAt: timestamp("updated_at", {
575
+ mode: "date",
576
+ withTimezone: true
577
+ }).notNull()
578
+ });
579
+ accounts = pgTable("account", {
580
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
581
+ userId: text("userId").notNull().references(() => users.id, { onDelete: "cascade" }),
582
+ accountId: text("account_id").notNull(),
583
+ providerId: text("provider_id").notNull(),
584
+ accessToken: text("access_token"),
585
+ refreshToken: text("refresh_token"),
586
+ idToken: text("id_token"),
587
+ accessTokenExpiresAt: timestamp("access_token_expires_at", {
588
+ mode: "date",
589
+ withTimezone: true
590
+ }),
591
+ refreshTokenExpiresAt: timestamp("refresh_token_expires_at", {
592
+ mode: "date",
593
+ withTimezone: true
594
+ }),
595
+ scope: text("scope"),
596
+ password: text("password"),
597
+ createdAt: timestamp("created_at", {
598
+ mode: "date",
599
+ withTimezone: true
600
+ }).notNull(),
601
+ updatedAt: timestamp("updated_at", {
602
+ mode: "date",
603
+ withTimezone: true
604
+ }).notNull()
605
+ }, (table) => [uniqueIndex("account_provider_providerId_idx").on(table.accountId, table.providerId)]);
606
+ sessions = pgTable("session", {
607
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
608
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
609
+ expiresAt: timestamp("expires_at", {
610
+ mode: "date",
611
+ withTimezone: true
612
+ }).notNull(),
613
+ token: text("token").notNull().unique(),
614
+ ipAddress: text("ip_address"),
615
+ userAgent: text("user_agent"),
616
+ createdAt: timestamp("created_at", {
617
+ mode: "date",
618
+ withTimezone: true
619
+ }).notNull(),
620
+ updatedAt: timestamp("updated_at", {
621
+ mode: "date",
622
+ withTimezone: true
623
+ }).notNull()
624
+ });
625
+ verification = pgTable("verification", {
626
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
627
+ identifier: text("identifier").notNull(),
628
+ value: text("value").notNull(),
629
+ expiresAt: timestamp("expires_at", {
630
+ mode: "date",
631
+ withTimezone: true
632
+ }).notNull(),
633
+ createdAt: timestamp("created_at", {
634
+ mode: "date",
635
+ withTimezone: true
636
+ }).notNull(),
637
+ updatedAt: timestamp("updated_at", {
638
+ mode: "date",
639
+ withTimezone: true
640
+ }).notNull()
641
+ });
642
+ });
643
+
644
+ // ../data/src/domains/developer/table.ts
645
+ import { pgTable as pgTable2, text as text2, timestamp as timestamp2, uuid, varchar } from "drizzle-orm/pg-core";
646
+ var developerKeys;
647
+ var init_table2 = __esm(() => {
648
+ init_table();
649
+ developerKeys = pgTable2("developer_keys", {
650
+ id: uuid("id").primaryKey().defaultRandom(),
651
+ userId: text2("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
652
+ label: varchar("label", { length: 255 }),
653
+ keyHash: text2("key_hash").notNull().unique(),
654
+ createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow()
655
+ });
656
+ });
657
+
658
+ // ../data/src/domains/map/table.ts
659
+ import { relations } from "drizzle-orm";
660
+ import {
661
+ doublePrecision,
662
+ jsonb,
663
+ pgEnum as pgEnum2,
664
+ pgTable as pgTable3,
665
+ text as text3,
666
+ uniqueIndex as uniqueIndex2,
667
+ uuid as uuid2,
668
+ varchar as varchar2
669
+ } from "drizzle-orm/pg-core";
670
+ var interactionTypeEnum, maps, mapElements, mapElementsRelations, mapsRelations;
671
+ var init_table3 = __esm(() => {
672
+ init_table4();
673
+ interactionTypeEnum = pgEnum2("interaction_type", [
674
+ "game_entry",
675
+ "game_registry",
676
+ "info",
677
+ "teleport",
678
+ "door_in",
679
+ "door_out",
680
+ "npc_interaction",
681
+ "quest_trigger"
682
+ ]);
683
+ maps = pgTable3("maps", {
684
+ id: uuid2("id").primaryKey().defaultRandom(),
685
+ identifier: varchar2("identifier", { length: 255 }).notNull().unique(),
686
+ displayName: varchar2("display_name", { length: 255 }).notNull(),
687
+ filePath: varchar2("file_path", { length: 255 }).notNull(),
688
+ tilesetBasePath: varchar2("tileset_base_path", { length: 255 }).notNull().default("/tilesets"),
689
+ defaultSpawnTileX: doublePrecision("default_spawn_tile_x").notNull().default(0),
690
+ defaultSpawnTileY: doublePrecision("default_spawn_tile_y").notNull().default(0),
691
+ description: text3("description")
692
+ });
693
+ mapElements = pgTable3("map_elements", {
694
+ id: uuid2("id").primaryKey().defaultRandom(),
695
+ mapId: uuid2("map_id").references(() => maps.id, {
696
+ onDelete: "cascade"
697
+ }),
698
+ elementSlug: varchar2("element_slug", { length: 255 }).notNull(),
699
+ interactionType: interactionTypeEnum("interaction_type").notNull(),
700
+ gameId: uuid2("game_id").references(() => games.id, {
701
+ onDelete: "set null"
702
+ }),
703
+ metadata: jsonb("metadata").$type().default({})
704
+ }, (table) => [uniqueIndex2("map_id_element_slug_unique_idx").on(table.mapId, table.elementSlug)]);
705
+ mapElementsRelations = relations(mapElements, ({ one }) => ({
706
+ game: one(games, {
707
+ fields: [mapElements.gameId],
708
+ references: [games.id]
709
+ }),
710
+ map: one(maps, {
711
+ fields: [mapElements.mapId],
712
+ references: [maps.id]
713
+ })
714
+ }));
715
+ mapsRelations = relations(maps, ({ many }) => ({
716
+ elements: many(mapElements)
717
+ }));
718
+ });
719
+
720
+ // ../data/src/domains/game/table.ts
721
+ import {
722
+ jsonb as jsonb2,
723
+ pgEnum as pgEnum3,
724
+ pgTable as pgTable4,
725
+ text as text4,
726
+ timestamp as timestamp3,
727
+ uniqueIndex as uniqueIndex3,
728
+ uuid as uuid3,
729
+ varchar as varchar3
730
+ } from "drizzle-orm/pg-core";
731
+ var gamePlatformEnum, gameBootModeEnum, games, gameSessions, gameStates;
732
+ var init_table4 = __esm(() => {
733
+ init_table3();
734
+ init_table();
735
+ gamePlatformEnum = pgEnum3("game_platform", ["web", "godot", "unity"]);
736
+ gameBootModeEnum = pgEnum3("game_boot_mode", ["iframe", "module"]);
737
+ games = pgTable4("games", {
738
+ id: uuid3("id").primaryKey().defaultRandom(),
739
+ developerId: text4("developer_id").references(() => users.id, {
740
+ onDelete: "set null"
741
+ }),
742
+ slug: varchar3("slug", { length: 255 }).notNull().unique(),
743
+ displayName: varchar3("display_name", { length: 255 }).notNull(),
744
+ version: varchar3("version", { length: 50 }).notNull(),
745
+ assetBundleBase: text4("asset_bundle_base").notNull(),
746
+ platform: gamePlatformEnum("platform").notNull().default("web"),
747
+ mapElementId: uuid3("map_element_id").references(() => mapElements.id, {
748
+ onDelete: "set null"
749
+ }),
750
+ metadata: jsonb2("metadata").default("{}"),
751
+ createdAt: timestamp3("created_at", { withTimezone: true }).defaultNow(),
752
+ updatedAt: timestamp3("updated_at", { withTimezone: true }).defaultNow()
753
+ });
754
+ gameSessions = pgTable4("game_sessions", {
755
+ id: uuid3("id").primaryKey().defaultRandom(),
756
+ userId: text4("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
757
+ gameId: uuid3("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
758
+ startedAt: timestamp3("started_at", { withTimezone: true }).notNull().defaultNow(),
759
+ endedAt: timestamp3("ended_at", { withTimezone: true })
760
+ });
761
+ gameStates = pgTable4("game_states", {
762
+ userId: text4("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
763
+ gameId: uuid3("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
764
+ data: jsonb2("data").default("{}"),
765
+ updatedAt: timestamp3("updated_at", { withTimezone: true }).defaultNow()
766
+ }, (table) => [uniqueIndex3("unique_user_game_idx").on(table.userId, table.gameId)]);
767
+ });
768
+
769
+ // ../data/src/domains/inventory/table.ts
770
+ import { relations as relations2, sql } from "drizzle-orm";
771
+ import {
772
+ boolean as boolean2,
773
+ integer,
774
+ jsonb as jsonb3,
775
+ pgEnum as pgEnum4,
776
+ pgTable as pgTable5,
777
+ text as text5,
778
+ timestamp as timestamp4,
779
+ uniqueIndex as uniqueIndex4,
780
+ uuid as uuid4
781
+ } from "drizzle-orm/pg-core";
782
+ var itemTypeEnum, items, inventoryItems, currencies, shopListings, itemsRelations, currenciesRelations, shopListingsRelations, inventoryItemsRelations;
783
+ var init_table5 = __esm(() => {
784
+ init_table4();
785
+ init_table();
786
+ itemTypeEnum = pgEnum4("item_type", [
787
+ "currency",
788
+ "badge",
789
+ "trophy",
790
+ "collectible",
791
+ "consumable",
792
+ "unlock",
793
+ "upgrade",
794
+ "other"
795
+ ]);
796
+ items = pgTable5("items", {
797
+ id: uuid4("id").primaryKey().defaultRandom(),
798
+ slug: text5("slug").notNull(),
799
+ gameId: uuid4("game_id").references(() => games.id, {
800
+ onDelete: "cascade"
801
+ }),
802
+ displayName: text5("display_name").notNull(),
803
+ description: text5("description"),
804
+ type: itemTypeEnum("type").notNull().default("other"),
805
+ imageUrl: text5("image_url"),
806
+ metadata: jsonb3("metadata").default({}),
807
+ createdAt: timestamp4("created_at").defaultNow().notNull()
808
+ }, (table) => [
809
+ uniqueIndex4("items_game_slug_idx").on(table.gameId, table.slug),
810
+ uniqueIndex4("items_global_slug_idx").on(table.slug).where(sql`game_id IS NULL`)
811
+ ]);
812
+ inventoryItems = pgTable5("inventory_items", {
813
+ id: uuid4("id").primaryKey().defaultRandom(),
814
+ userId: text5("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
815
+ itemId: uuid4("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
816
+ quantity: integer("quantity").notNull().default(1),
817
+ updatedAt: timestamp4("updated_at", { withTimezone: true }).defaultNow()
818
+ }, (table) => [uniqueIndex4("unique_user_item_idx").on(table.userId, table.itemId)]);
819
+ currencies = pgTable5("currencies", {
820
+ id: uuid4("id").primaryKey().defaultRandom(),
821
+ itemId: uuid4("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
822
+ symbol: text5("symbol"),
823
+ isPrimary: boolean2("is_primary").default(false).notNull(),
824
+ createdAt: timestamp4("created_at").defaultNow().notNull(),
825
+ updatedAt: timestamp4("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
826
+ }, (table) => [uniqueIndex4("currency_item_id_idx").on(table.itemId)]);
827
+ shopListings = pgTable5("shop_listings", {
828
+ id: uuid4("id").primaryKey().defaultRandom(),
829
+ itemId: uuid4("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
830
+ currencyId: uuid4("currency_id").notNull().references(() => currencies.id, { onDelete: "restrict" }),
831
+ price: integer("price").notNull(),
832
+ sellBackPercentage: integer("sell_back_percentage"),
833
+ stock: integer("stock"),
834
+ isActive: boolean2("is_active").default(true).notNull(),
835
+ availableFrom: timestamp4("available_from", { withTimezone: true }),
836
+ availableUntil: timestamp4("available_until", { withTimezone: true }),
837
+ createdAt: timestamp4("created_at").defaultNow().notNull(),
838
+ updatedAt: timestamp4("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
839
+ }, (table) => [uniqueIndex4("unique_item_currency_listing_idx").on(table.itemId, table.currencyId)]);
840
+ itemsRelations = relations2(items, ({ many }) => ({
841
+ shopListings: many(shopListings),
842
+ inventoryItems: many(inventoryItems)
843
+ }));
844
+ currenciesRelations = relations2(currencies, ({ many }) => ({
845
+ shopListings: many(shopListings)
846
+ }));
847
+ shopListingsRelations = relations2(shopListings, ({ one }) => ({
848
+ item: one(items, {
849
+ fields: [shopListings.itemId],
850
+ references: [items.id]
851
+ }),
852
+ currency: one(currencies, {
853
+ fields: [shopListings.currencyId],
854
+ references: [currencies.id]
855
+ })
856
+ }));
857
+ inventoryItemsRelations = relations2(inventoryItems, ({ one }) => ({
858
+ item: one(items, {
859
+ fields: [inventoryItems.itemId],
860
+ references: [items.id]
861
+ }),
862
+ user: one(users, {
863
+ fields: [inventoryItems.userId],
864
+ references: [users.id]
865
+ })
866
+ }));
867
+ });
868
+
869
+ // ../data/src/domains/level/table.ts
870
+ import { relations as relations3 } from "drizzle-orm";
871
+ import { integer as integer2, pgTable as pgTable6, text as text6, timestamp as timestamp5, uniqueIndex as uniqueIndex5, uuid as uuid5 } from "drizzle-orm/pg-core";
872
+ var userLevels, levelConfigs, userLevelsRelations;
873
+ var init_table6 = __esm(() => {
874
+ init_table();
875
+ userLevels = pgTable6("user_levels", {
876
+ userId: text6("user_id").primaryKey().references(() => users.id, { onDelete: "cascade" }),
877
+ currentLevel: integer2("current_level").notNull().default(1),
878
+ currentXp: integer2("current_xp").notNull().default(0),
879
+ totalXP: integer2("total_xp").notNull().default(0),
880
+ lastLevelUpAt: timestamp5("last_level_up_at", { withTimezone: true }),
881
+ createdAt: timestamp5("created_at").defaultNow().notNull(),
882
+ updatedAt: timestamp5("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
883
+ });
884
+ levelConfigs = pgTable6("level_configs", {
885
+ id: uuid5("id").primaryKey().defaultRandom(),
886
+ level: integer2("level").notNull().unique(),
887
+ xpRequired: integer2("xp_required").notNull(),
888
+ creditsReward: integer2("credits_reward").notNull().default(0),
889
+ createdAt: timestamp5("created_at").defaultNow().notNull()
890
+ }, (table) => [uniqueIndex5("unique_level_config_idx").on(table.level)]);
891
+ userLevelsRelations = relations3(userLevels, ({ one }) => ({
892
+ user: one(users, {
893
+ fields: [userLevels.userId],
894
+ references: [users.id]
895
+ })
896
+ }));
897
+ });
898
+
899
+ // ../data/src/tables.index.ts
900
+ var init_tables_index = __esm(() => {
901
+ init_table();
902
+ init_table2();
903
+ init_table4();
904
+ init_table5();
905
+ init_table3();
906
+ init_table6();
907
+ });
908
+
440
909
  // ../data/src/constants.ts
441
- var ITEM_INTERNAL_NAMES, CURRENCIES, BADGES;
910
+ var ITEM_SLUGS, CURRENCIES, BADGES, INTERACTION_TYPE;
442
911
  var init_constants = __esm(() => {
443
- ITEM_INTERNAL_NAMES = {
912
+ init_tables_index();
913
+ ITEM_SLUGS = {
444
914
  PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
445
915
  PLAYCADEMY_XP: "PLAYCADEMY_XP",
446
916
  FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
@@ -451,14 +921,15 @@ var init_constants = __esm(() => {
451
921
  SMALL_BACKPACK: "SMALL_BACKPACK"
452
922
  };
453
923
  CURRENCIES = {
454
- PRIMARY: ITEM_INTERNAL_NAMES.PLAYCADEMY_CREDITS,
455
- XP: ITEM_INTERNAL_NAMES.PLAYCADEMY_XP
924
+ PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
925
+ XP: ITEM_SLUGS.PLAYCADEMY_XP
456
926
  };
457
927
  BADGES = {
458
- FOUNDING_MEMBER: ITEM_INTERNAL_NAMES.FOUNDING_MEMBER_BADGE,
459
- EARLY_ADOPTER: ITEM_INTERNAL_NAMES.EARLY_ADOPTER_BADGE,
460
- FIRST_GAME: ITEM_INTERNAL_NAMES.FIRST_GAME_BADGE
928
+ FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
929
+ EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
930
+ FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
461
931
  };
932
+ INTERACTION_TYPE = Object.fromEntries(interactionTypeEnum.enumValues.map((value) => [value, value]));
462
933
  });
463
934
 
464
935
  // src/core/namespaces/credits.ts
@@ -468,9 +939,9 @@ function createCreditsNamespace(client) {
468
939
  if (cachedCreditsItemId) {
469
940
  return cachedCreditsItemId;
470
941
  }
471
- const items = await client.admin.items.list();
472
- const creditsItem = items.find((item) => item.internalName === CURRENCIES.PRIMARY);
473
- if (!creditsItem) {
942
+ const queryParams = new URLSearchParams({ slug: CURRENCIES.PRIMARY });
943
+ const creditsItem = await client["request"](`/items/resolve?${queryParams.toString()}`, "GET");
944
+ if (!creditsItem || !creditsItem.id) {
474
945
  throw new Error("Playcademy Credits item not found in catalog");
475
946
  }
476
947
  cachedCreditsItemId = creditsItem.id;
@@ -479,8 +950,8 @@ function createCreditsNamespace(client) {
479
950
  return {
480
951
  balance: async () => {
481
952
  const inventory = await client.users.inventory.get();
482
- const creditsItem = inventory.find((item) => item.item?.internalName === CURRENCIES.PRIMARY);
483
- return creditsItem?.quantity ?? 0;
953
+ const primaryCurrencyInventoryItem = inventory.find((item) => item.item?.slug === CURRENCIES.PRIMARY);
954
+ return primaryCurrencyInventoryItem?.quantity ?? 0;
484
955
  },
485
956
  add: async (amount) => {
486
957
  if (amount <= 0) {
@@ -606,13 +1077,14 @@ async function login(baseUrl, email, password) {
606
1077
  const errorMessage = errorData && errorData.message ? String(errorData.message) : response.statusText;
607
1078
  throw new PlaycademyError(errorMessage);
608
1079
  } catch (error) {
609
- console.error("[SDK] Failed to parse error response JSON, using status text instead:", error);
1080
+ log.error("[Playcademy SDK] Failed to parse error response JSON, using status text instead:", { error });
610
1081
  throw new PlaycademyError(response.statusText);
611
1082
  }
612
1083
  }
613
1084
  return response.json();
614
1085
  }
615
1086
  var init_login = __esm(() => {
1087
+ init_src();
616
1088
  init_errors();
617
1089
  });
618
1090
 
@@ -629,9 +1101,10 @@ __export(exports_client, {
629
1101
  });
630
1102
  var PlaycademyClient;
631
1103
  var init_client = __esm(() => {
1104
+ init_src();
632
1105
  init_errors();
633
- init_request();
634
1106
  init_namespaces();
1107
+ init_request();
635
1108
  init_static();
636
1109
  PlaycademyClient = class PlaycademyClient {
637
1110
  baseUrl;
@@ -651,14 +1124,16 @@ var init_client = __esm(() => {
651
1124
  }
652
1125
  if (this.gameId) {
653
1126
  this._initializeInternalSession().catch((error) => {
654
- console.error("[SDK] Background initialization of auto-session failed:", error);
1127
+ log.error("[Playcademy SDK] Background initialization of auto-session failed:", {
1128
+ error
1129
+ });
655
1130
  });
656
1131
  }
657
1132
  }
658
1133
  getBaseUrl() {
659
1134
  const isRelative = this.baseUrl.startsWith("/");
660
- const isBrowser = typeof window !== "undefined";
661
- return isRelative && isBrowser ? `${window.location.origin}${this.baseUrl}` : this.baseUrl;
1135
+ const isBrowser2 = typeof window !== "undefined";
1136
+ return isRelative && isBrowser2 ? `${window.location.origin}${this.baseUrl}` : this.baseUrl;
662
1137
  }
663
1138
  ping() {
664
1139
  return "pong";
@@ -704,7 +1179,10 @@ var init_client = __esm(() => {
704
1179
  const response = await this.games.startSession(this.gameId);
705
1180
  this.internalClientSessionId = response.sessionId;
706
1181
  } catch (error) {
707
- console.error("[SDK] Auto-starting session failed for game", this.gameId, error);
1182
+ log.error("[Playcademy SDK] Auto-starting session failed for game", {
1183
+ gameId: this.gameId,
1184
+ error
1185
+ });
708
1186
  }
709
1187
  }
710
1188
  auth = createAuthNamespace(this);