@playcademy/sdk 0.0.1-beta.27 → 0.0.1-beta.29

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
@@ -175,7 +175,8 @@ class PlaycademyMessaging {
175
175
  const iframeToParentEvents = [
176
176
  "PLAYCADEMY_READY" /* READY */,
177
177
  "PLAYCADEMY_EXIT" /* EXIT */,
178
- "PLAYCADEMY_TELEMETRY" /* TELEMETRY */
178
+ "PLAYCADEMY_TELEMETRY" /* TELEMETRY */,
179
+ "PLAYCADEMY_KEY_EVENT" /* KEY_EVENT */
179
180
  ];
180
181
  const shouldUsePostMessage = isIframe && iframeToParentEvents.includes(eventType);
181
182
  return {
@@ -207,12 +208,49 @@ var init_messaging = __esm(() => {
207
208
  MessageEvents2["READY"] = "PLAYCADEMY_READY";
208
209
  MessageEvents2["EXIT"] = "PLAYCADEMY_EXIT";
209
210
  MessageEvents2["TELEMETRY"] = "PLAYCADEMY_TELEMETRY";
211
+ MessageEvents2["KEY_EVENT"] = "PLAYCADEMY_KEY_EVENT";
210
212
  })(MessageEvents ||= {});
211
213
  messaging = new PlaycademyMessaging;
212
214
  });
213
215
 
214
216
  // src/core/namespaces/runtime.ts
215
217
  function createRuntimeNamespace(client) {
218
+ const eventListeners = new Map;
219
+ const trackListener = (eventType, handler) => {
220
+ if (!eventListeners.has(eventType)) {
221
+ eventListeners.set(eventType, new Set);
222
+ }
223
+ eventListeners.get(eventType).add(handler);
224
+ };
225
+ const untrackListener = (eventType, handler) => {
226
+ const listeners = eventListeners.get(eventType);
227
+ if (listeners) {
228
+ listeners.delete(handler);
229
+ if (listeners.size === 0) {
230
+ eventListeners.delete(eventType);
231
+ }
232
+ }
233
+ };
234
+ if (typeof window !== "undefined" && window.self !== window.top) {
235
+ const playcademyConfig = window.PLAYCADEMY;
236
+ const forwardKeys = Array.isArray(playcademyConfig?.forwardKeys) ? playcademyConfig.forwardKeys : ["Escape"];
237
+ const keySet = new Set(forwardKeys.map((k) => k.toLowerCase()));
238
+ const keyListener = (event) => {
239
+ if (keySet.has(event.key.toLowerCase()) || keySet.has(event.code.toLowerCase())) {
240
+ messaging.send("PLAYCADEMY_KEY_EVENT" /* KEY_EVENT */, {
241
+ key: event.key,
242
+ code: event.code,
243
+ type: event.type
244
+ });
245
+ }
246
+ };
247
+ window.addEventListener("keydown", keyListener);
248
+ window.addEventListener("keyup", keyListener);
249
+ trackListener("PLAYCADEMY_FORCE_EXIT" /* FORCE_EXIT */, () => {
250
+ window.removeEventListener("keydown", keyListener);
251
+ window.removeEventListener("keyup", keyListener);
252
+ });
253
+ }
216
254
  return {
217
255
  getGameToken: async (gameId, options) => {
218
256
  const res = await client["request"](`/games/${gameId}/token`, "POST");
@@ -233,6 +271,55 @@ function createRuntimeNamespace(client) {
233
271
  }
234
272
  }
235
273
  messaging.send("PLAYCADEMY_EXIT" /* EXIT */, undefined);
274
+ },
275
+ onInit: (handler) => {
276
+ messaging.listen("PLAYCADEMY_INIT" /* INIT */, handler);
277
+ trackListener("PLAYCADEMY_INIT" /* INIT */, handler);
278
+ },
279
+ onTokenRefresh: (handler) => {
280
+ messaging.listen("PLAYCADEMY_TOKEN_REFRESH" /* TOKEN_REFRESH */, handler);
281
+ trackListener("PLAYCADEMY_TOKEN_REFRESH" /* TOKEN_REFRESH */, handler);
282
+ },
283
+ onPause: (handler) => {
284
+ messaging.listen("PLAYCADEMY_PAUSE" /* PAUSE */, handler);
285
+ trackListener("PLAYCADEMY_PAUSE" /* PAUSE */, handler);
286
+ },
287
+ onResume: (handler) => {
288
+ messaging.listen("PLAYCADEMY_RESUME" /* RESUME */, handler);
289
+ trackListener("PLAYCADEMY_RESUME" /* RESUME */, handler);
290
+ },
291
+ onForceExit: (handler) => {
292
+ messaging.listen("PLAYCADEMY_FORCE_EXIT" /* FORCE_EXIT */, handler);
293
+ trackListener("PLAYCADEMY_FORCE_EXIT" /* FORCE_EXIT */, handler);
294
+ },
295
+ onOverlay: (handler) => {
296
+ messaging.listen("PLAYCADEMY_OVERLAY" /* OVERLAY */, handler);
297
+ trackListener("PLAYCADEMY_OVERLAY" /* OVERLAY */, handler);
298
+ },
299
+ ready: () => {
300
+ messaging.send("PLAYCADEMY_READY" /* READY */, undefined);
301
+ },
302
+ sendTelemetry: (data) => {
303
+ messaging.send("PLAYCADEMY_TELEMETRY" /* TELEMETRY */, data);
304
+ },
305
+ removeListener: (eventType, handler) => {
306
+ messaging.unlisten(eventType, handler);
307
+ untrackListener(eventType, handler);
308
+ },
309
+ removeAllListeners: () => {
310
+ for (const [eventType, handlers] of eventListeners.entries()) {
311
+ for (const handler of handlers) {
312
+ messaging.unlisten(eventType, handler);
313
+ }
314
+ }
315
+ eventListeners.clear();
316
+ },
317
+ getListenerCounts: () => {
318
+ const counts = {};
319
+ for (const [eventType, handlers] of eventListeners.entries()) {
320
+ counts[eventType] = handlers.size;
321
+ }
322
+ return counts;
236
323
  }
237
324
  };
238
325
  }
@@ -336,6 +423,27 @@ function createGamesNamespace(client) {
336
423
  client["internalClientSessionId"] = undefined;
337
424
  }
338
425
  await client["request"](`/games/${effectiveGameIdToEnd}/sessions/${sessionId}/end`, "POST");
426
+ },
427
+ token: {
428
+ create: async (gameId, options) => {
429
+ const res = await client["request"](`/games/${gameId}/token`, "POST");
430
+ if (options?.apply) {
431
+ client.setToken(res.token);
432
+ }
433
+ return res;
434
+ }
435
+ },
436
+ leaderboard: {
437
+ get: async (gameId, options) => {
438
+ const params = new URLSearchParams;
439
+ if (options?.limit)
440
+ params.append("limit", String(options.limit));
441
+ if (options?.offset)
442
+ params.append("offset", String(options.offset));
443
+ const queryString = params.toString();
444
+ const path = queryString ? `/games/${gameId}/leaderboard?${queryString}` : `/games/${gameId}/leaderboard`;
445
+ return client["request"](path, "GET");
446
+ }
339
447
  }
340
448
  };
341
449
  }
@@ -401,6 +509,27 @@ function createUsersNamespace(client) {
401
509
  const qty = item?.quantity ?? 0;
402
510
  return qty >= minQuantity;
403
511
  }
512
+ },
513
+ scores: {
514
+ get: async (userIdOrOptions, options) => {
515
+ let userId;
516
+ let queryOptions;
517
+ if (typeof userIdOrOptions === "string") {
518
+ userId = userIdOrOptions;
519
+ queryOptions = options || {};
520
+ } else {
521
+ queryOptions = userIdOrOptions || {};
522
+ const user = await client["request"]("/users/me", "GET");
523
+ userId = user.id;
524
+ }
525
+ const params = new URLSearchParams({
526
+ limit: String(queryOptions.limit || 50)
527
+ });
528
+ if (queryOptions.gameId) {
529
+ params.append("gameId", queryOptions.gameId);
530
+ }
531
+ return client["request"](`/users/${userId}/scores?${params}`, "GET");
532
+ }
404
533
  }
405
534
  };
406
535
  }
@@ -410,7 +539,7 @@ function createDevNamespace(client) {
410
539
  return {
411
540
  auth: {
412
541
  applyForDeveloper: () => client["request"]("/dev/apply", "POST"),
413
- getDeveloperStatus: async () => {
542
+ getStatus: async () => {
414
543
  const response = await client["request"]("/dev/status", "GET");
415
544
  return response.status;
416
545
  }
@@ -478,9 +607,9 @@ function createDevNamespace(client) {
478
607
  delete: (gameId) => client["request"](`/games/${gameId}`, "DELETE")
479
608
  },
480
609
  keys: {
481
- createKey: (label) => client["request"](`/dev/keys`, "POST", { label }),
482
- listKeys: () => client["request"](`/dev/keys`, "GET"),
483
- revokeKey: (keyId) => client["request"](`/dev/keys/${keyId}`, "DELETE")
610
+ create: (label) => client["request"](`/dev/keys`, "POST", { label }),
611
+ list: () => client["request"](`/dev/keys`, "GET"),
612
+ revoke: (keyId) => client["request"](`/dev/keys/${keyId}`, "DELETE")
484
613
  },
485
614
  items: {
486
615
  create: (gameId, slug, itemData) => client["request"](`/games/${gameId}/items`, "POST", {
@@ -518,7 +647,13 @@ function createDevNamespace(client) {
518
647
  // src/core/namespaces/maps.ts
519
648
  function createMapsNamespace(client) {
520
649
  return {
521
- elements: (mapId) => client["request"](`/map/elements?mapId=${mapId}`, "GET")
650
+ get: (identifier) => client["request"](`/maps/${identifier}`, "GET"),
651
+ elements: (mapId) => client["request"](`/map/elements?mapId=${mapId}`, "GET"),
652
+ objects: {
653
+ list: (mapId) => client["request"](`/maps/${mapId}/objects`, "GET"),
654
+ create: (mapId, objectData) => client["request"](`/maps/${mapId}/objects`, "POST", objectData),
655
+ delete: (mapId, objectId) => client["request"](`/maps/${mapId}/objects/${objectId}`, "DELETE")
656
+ }
522
657
  };
523
658
  }
524
659
 
@@ -608,125 +743,180 @@ function createLevelsNamespace(client) {
608
743
  };
609
744
  }
610
745
 
611
- // ../data/src/domains/user/table.ts
612
- import { boolean, pgEnum, pgTable, text, timestamp, uniqueIndex } from "drizzle-orm/pg-core";
613
- var userRoleEnum, developerStatusEnum, users, accounts, sessions, verification;
746
+ // ../data/src/domains/game/table.ts
747
+ import {
748
+ jsonb,
749
+ pgEnum,
750
+ pgTable,
751
+ text,
752
+ timestamp,
753
+ uniqueIndex,
754
+ uuid,
755
+ varchar
756
+ } from "drizzle-orm/pg-core";
757
+ var gamePlatformEnum, gameBootModeEnum, games, gameSessions, gameStates;
614
758
  var init_table = __esm(() => {
615
- userRoleEnum = pgEnum("user_role", ["admin", "player", "developer"]);
616
- developerStatusEnum = pgEnum("developer_status", ["none", "pending", "approved"]);
617
- users = pgTable("user", {
618
- id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
619
- name: text("name").notNull(),
620
- username: text("username").unique(),
621
- email: text("email").notNull().unique(),
622
- emailVerified: boolean("email_verified").notNull().default(false),
623
- image: text("image"),
624
- role: userRoleEnum("role").notNull().default("player"),
625
- developerStatus: developerStatusEnum("developer_status").notNull().default("none"),
626
- createdAt: timestamp("created_at", {
627
- mode: "date",
628
- withTimezone: true
629
- }).notNull(),
630
- updatedAt: timestamp("updated_at", {
631
- mode: "date",
632
- withTimezone: true
633
- }).notNull()
634
- });
635
- accounts = pgTable("account", {
636
- id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
637
- userId: text("userId").notNull().references(() => users.id, { onDelete: "cascade" }),
638
- accountId: text("account_id").notNull(),
639
- providerId: text("provider_id").notNull(),
640
- accessToken: text("access_token"),
641
- refreshToken: text("refresh_token"),
642
- idToken: text("id_token"),
643
- accessTokenExpiresAt: timestamp("access_token_expires_at", {
644
- mode: "date",
645
- withTimezone: true
759
+ init_table3();
760
+ init_table4();
761
+ gamePlatformEnum = pgEnum("game_platform", ["web", "godot", "unity"]);
762
+ gameBootModeEnum = pgEnum("game_boot_mode", ["iframe", "module"]);
763
+ games = pgTable("games", {
764
+ id: uuid("id").primaryKey().defaultRandom(),
765
+ developerId: text("developer_id").references(() => users.id, {
766
+ onDelete: "set null"
646
767
  }),
647
- refreshTokenExpiresAt: timestamp("refresh_token_expires_at", {
648
- mode: "date",
649
- withTimezone: true
768
+ slug: varchar("slug", { length: 255 }).notNull().unique(),
769
+ displayName: varchar("display_name", { length: 255 }).notNull(),
770
+ version: varchar("version", { length: 50 }).notNull(),
771
+ assetBundleBase: text("asset_bundle_base").notNull(),
772
+ platform: gamePlatformEnum("platform").notNull().default("web"),
773
+ mapElementId: uuid("map_element_id").references(() => mapElements.id, {
774
+ onDelete: "set null"
650
775
  }),
651
- scope: text("scope"),
652
- password: text("password"),
653
- createdAt: timestamp("created_at", {
654
- mode: "date",
655
- withTimezone: true
656
- }).notNull(),
657
- updatedAt: timestamp("updated_at", {
658
- mode: "date",
659
- withTimezone: true
660
- }).notNull()
661
- }, (table) => [uniqueIndex("account_provider_providerId_idx").on(table.accountId, table.providerId)]);
662
- sessions = pgTable("session", {
663
- id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
664
- userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
665
- expiresAt: timestamp("expires_at", {
666
- mode: "date",
667
- withTimezone: true
668
- }).notNull(),
669
- token: text("token").notNull().unique(),
670
- ipAddress: text("ip_address"),
671
- userAgent: text("user_agent"),
672
- createdAt: timestamp("created_at", {
673
- mode: "date",
674
- withTimezone: true
675
- }).notNull(),
676
- updatedAt: timestamp("updated_at", {
677
- mode: "date",
678
- withTimezone: true
679
- }).notNull()
776
+ metadata: jsonb("metadata").default("{}"),
777
+ createdAt: timestamp("created_at", { withTimezone: true }).defaultNow(),
778
+ updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow()
680
779
  });
681
- verification = pgTable("verification", {
682
- id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
683
- identifier: text("identifier").notNull(),
684
- value: text("value").notNull(),
685
- expiresAt: timestamp("expires_at", {
686
- mode: "date",
687
- withTimezone: true
688
- }).notNull(),
689
- createdAt: timestamp("created_at", {
690
- mode: "date",
691
- withTimezone: true
692
- }).notNull(),
693
- updatedAt: timestamp("updated_at", {
694
- mode: "date",
695
- withTimezone: true
696
- }).notNull()
780
+ gameSessions = pgTable("game_sessions", {
781
+ id: uuid("id").primaryKey().defaultRandom(),
782
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
783
+ gameId: uuid("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
784
+ startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
785
+ endedAt: timestamp("ended_at", { withTimezone: true })
697
786
  });
787
+ gameStates = pgTable("game_states", {
788
+ userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
789
+ gameId: uuid("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
790
+ data: jsonb("data").default("{}"),
791
+ updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow()
792
+ }, (table) => [uniqueIndex("unique_user_game_idx").on(table.userId, table.gameId)]);
698
793
  });
699
794
 
700
- // ../data/src/domains/developer/table.ts
701
- import { pgTable as pgTable2, text as text2, timestamp as timestamp2, uuid, varchar } from "drizzle-orm/pg-core";
702
- var developerKeys;
795
+ // ../data/src/domains/inventory/table.ts
796
+ import { relations, sql } from "drizzle-orm";
797
+ import {
798
+ boolean,
799
+ integer,
800
+ jsonb as jsonb2,
801
+ pgEnum as pgEnum2,
802
+ pgTable as pgTable2,
803
+ text as text2,
804
+ timestamp as timestamp2,
805
+ uniqueIndex as uniqueIndex2,
806
+ uuid as uuid2
807
+ } from "drizzle-orm/pg-core";
808
+ var itemTypeEnum, items, inventoryItems, currencies, shopListings, itemsRelations, currenciesRelations, shopListingsRelations, inventoryItemsRelations;
703
809
  var init_table2 = __esm(() => {
704
810
  init_table();
705
- developerKeys = pgTable2("developer_keys", {
706
- id: uuid("id").primaryKey().defaultRandom(),
811
+ init_table3();
812
+ init_table4();
813
+ itemTypeEnum = pgEnum2("item_type", [
814
+ "currency",
815
+ "badge",
816
+ "trophy",
817
+ "collectible",
818
+ "consumable",
819
+ "unlock",
820
+ "upgrade",
821
+ "accessory",
822
+ "other"
823
+ ]);
824
+ items = pgTable2("items", {
825
+ id: uuid2("id").primaryKey().defaultRandom(),
826
+ slug: text2("slug").notNull(),
827
+ gameId: uuid2("game_id").references(() => games.id, {
828
+ onDelete: "cascade"
829
+ }),
830
+ displayName: text2("display_name").notNull(),
831
+ description: text2("description"),
832
+ type: itemTypeEnum("type").notNull().default("other"),
833
+ isPlaceable: boolean("is_placeable").default(false).notNull(),
834
+ imageUrl: text2("image_url"),
835
+ metadata: jsonb2("metadata").default({}),
836
+ createdAt: timestamp2("created_at").defaultNow().notNull()
837
+ }, (table) => [
838
+ uniqueIndex2("items_game_slug_idx").on(table.gameId, table.slug),
839
+ uniqueIndex2("items_global_slug_idx").on(table.slug).where(sql`game_id IS NULL`)
840
+ ]);
841
+ inventoryItems = pgTable2("inventory_items", {
842
+ id: uuid2("id").primaryKey().defaultRandom(),
707
843
  userId: text2("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
708
- label: varchar("label", { length: 255 }),
709
- keyHash: text2("key_hash").notNull().unique(),
710
- createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow()
711
- });
844
+ itemId: uuid2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
845
+ quantity: integer("quantity").notNull().default(1),
846
+ updatedAt: timestamp2("updated_at", { withTimezone: true }).defaultNow()
847
+ }, (table) => [uniqueIndex2("unique_user_item_idx").on(table.userId, table.itemId)]);
848
+ currencies = pgTable2("currencies", {
849
+ id: uuid2("id").primaryKey().defaultRandom(),
850
+ itemId: uuid2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
851
+ symbol: text2("symbol"),
852
+ isPrimary: boolean("is_primary").default(false).notNull(),
853
+ createdAt: timestamp2("created_at").defaultNow().notNull(),
854
+ updatedAt: timestamp2("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
855
+ }, (table) => [uniqueIndex2("currency_item_id_idx").on(table.itemId)]);
856
+ shopListings = pgTable2("shop_listings", {
857
+ id: uuid2("id").primaryKey().defaultRandom(),
858
+ itemId: uuid2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
859
+ currencyId: uuid2("currency_id").notNull().references(() => currencies.id, { onDelete: "restrict" }),
860
+ price: integer("price").notNull(),
861
+ sellBackPercentage: integer("sell_back_percentage"),
862
+ stock: integer("stock"),
863
+ isActive: boolean("is_active").default(true).notNull(),
864
+ availableFrom: timestamp2("available_from", { withTimezone: true }),
865
+ availableUntil: timestamp2("available_until", { withTimezone: true }),
866
+ createdAt: timestamp2("created_at").defaultNow().notNull(),
867
+ updatedAt: timestamp2("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
868
+ }, (table) => [uniqueIndex2("unique_item_currency_listing_idx").on(table.itemId, table.currencyId)]);
869
+ itemsRelations = relations(items, ({ many }) => ({
870
+ shopListings: many(shopListings),
871
+ inventoryItems: many(inventoryItems),
872
+ mapObjects: many(mapObjects)
873
+ }));
874
+ currenciesRelations = relations(currencies, ({ many }) => ({
875
+ shopListings: many(shopListings)
876
+ }));
877
+ shopListingsRelations = relations(shopListings, ({ one }) => ({
878
+ item: one(items, {
879
+ fields: [shopListings.itemId],
880
+ references: [items.id]
881
+ }),
882
+ currency: one(currencies, {
883
+ fields: [shopListings.currencyId],
884
+ references: [currencies.id]
885
+ })
886
+ }));
887
+ inventoryItemsRelations = relations(inventoryItems, ({ one }) => ({
888
+ item: one(items, {
889
+ fields: [inventoryItems.itemId],
890
+ references: [items.id]
891
+ }),
892
+ user: one(users, {
893
+ fields: [inventoryItems.userId],
894
+ references: [users.id]
895
+ })
896
+ }));
712
897
  });
713
898
 
714
899
  // ../data/src/domains/map/table.ts
715
- import { relations } from "drizzle-orm";
900
+ import { relations as relations2 } from "drizzle-orm";
716
901
  import {
717
902
  doublePrecision,
718
- jsonb,
719
- pgEnum as pgEnum2,
903
+ index,
904
+ integer as integer2,
905
+ jsonb as jsonb3,
906
+ pgEnum as pgEnum3,
720
907
  pgTable as pgTable3,
721
908
  text as text3,
722
- uniqueIndex as uniqueIndex2,
723
- uuid as uuid2,
909
+ timestamp as timestamp3,
910
+ uniqueIndex as uniqueIndex3,
911
+ uuid as uuid3,
724
912
  varchar as varchar2
725
913
  } from "drizzle-orm/pg-core";
726
- var interactionTypeEnum, maps, mapElements, mapElementsRelations, mapsRelations;
914
+ var interactionTypeEnum, maps, mapElements, mapObjects, mapElementsRelations, mapsRelations, mapObjectsRelations;
727
915
  var init_table3 = __esm(() => {
916
+ init_table();
917
+ init_table2();
728
918
  init_table4();
729
- interactionTypeEnum = pgEnum2("interaction_type", [
919
+ interactionTypeEnum = pgEnum3("interaction_type", [
730
920
  "game_entry",
731
921
  "game_registry",
732
922
  "info",
@@ -737,7 +927,7 @@ var init_table3 = __esm(() => {
737
927
  "quest_trigger"
738
928
  ]);
739
929
  maps = pgTable3("maps", {
740
- id: uuid2("id").primaryKey().defaultRandom(),
930
+ id: uuid3("id").primaryKey().defaultRandom(),
741
931
  identifier: varchar2("identifier", { length: 255 }).notNull().unique(),
742
932
  displayName: varchar2("display_name", { length: 255 }).notNull(),
743
933
  filePath: varchar2("file_path", { length: 255 }).notNull(),
@@ -747,18 +937,32 @@ var init_table3 = __esm(() => {
747
937
  description: text3("description")
748
938
  });
749
939
  mapElements = pgTable3("map_elements", {
750
- id: uuid2("id").primaryKey().defaultRandom(),
751
- mapId: uuid2("map_id").references(() => maps.id, {
940
+ id: uuid3("id").primaryKey().defaultRandom(),
941
+ mapId: uuid3("map_id").references(() => maps.id, {
752
942
  onDelete: "cascade"
753
943
  }),
754
944
  elementSlug: varchar2("element_slug", { length: 255 }).notNull(),
755
945
  interactionType: interactionTypeEnum("interaction_type").notNull(),
756
- gameId: uuid2("game_id").references(() => games.id, {
946
+ gameId: uuid3("game_id").references(() => games.id, {
757
947
  onDelete: "set null"
758
948
  }),
759
- metadata: jsonb("metadata").$type().default({})
760
- }, (table) => [uniqueIndex2("map_id_element_slug_unique_idx").on(table.mapId, table.elementSlug)]);
761
- mapElementsRelations = relations(mapElements, ({ one }) => ({
949
+ metadata: jsonb3("metadata").$type().default({})
950
+ }, (table) => [uniqueIndex3("map_id_element_slug_unique_idx").on(table.mapId, table.elementSlug)]);
951
+ mapObjects = pgTable3("map_objects", {
952
+ id: uuid3("id").primaryKey().defaultRandom(),
953
+ userId: text3("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
954
+ mapId: uuid3("map_id").notNull().references(() => maps.id, { onDelete: "cascade" }),
955
+ itemId: uuid3("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
956
+ worldX: doublePrecision("world_x").notNull(),
957
+ worldY: doublePrecision("world_y").notNull(),
958
+ rotation: integer2("rotation").default(0).notNull(),
959
+ scale: doublePrecision("scale").default(1).notNull(),
960
+ createdAt: timestamp3("created_at").defaultNow().notNull()
961
+ }, (table) => [
962
+ index("map_objects_map_idx").on(table.mapId),
963
+ index("map_objects_spatial_idx").on(table.mapId, table.worldX, table.worldY)
964
+ ]);
965
+ mapElementsRelations = relations2(mapElements, ({ one }) => ({
762
966
  game: one(games, {
763
967
  fields: [mapElements.gameId],
764
968
  references: [games.id]
@@ -768,183 +972,158 @@ var init_table3 = __esm(() => {
768
972
  references: [maps.id]
769
973
  })
770
974
  }));
771
- mapsRelations = relations(maps, ({ many }) => ({
772
- elements: many(mapElements)
975
+ mapsRelations = relations2(maps, ({ many }) => ({
976
+ elements: many(mapElements),
977
+ objects: many(mapObjects)
978
+ }));
979
+ mapObjectsRelations = relations2(mapObjects, ({ one }) => ({
980
+ user: one(users, {
981
+ fields: [mapObjects.userId],
982
+ references: [users.id]
983
+ }),
984
+ map: one(maps, {
985
+ fields: [mapObjects.mapId],
986
+ references: [maps.id]
987
+ }),
988
+ item: one(items, {
989
+ fields: [mapObjects.itemId],
990
+ references: [items.id]
991
+ })
773
992
  }));
774
993
  });
775
994
 
776
- // ../data/src/domains/game/table.ts
777
- import {
778
- jsonb as jsonb2,
779
- pgEnum as pgEnum3,
780
- pgTable as pgTable4,
781
- text as text4,
782
- timestamp as timestamp3,
783
- uniqueIndex as uniqueIndex3,
784
- uuid as uuid3,
785
- varchar as varchar3
786
- } from "drizzle-orm/pg-core";
787
- var gamePlatformEnum, gameBootModeEnum, games, gameSessions, gameStates;
995
+ // ../data/src/domains/user/table.ts
996
+ import { relations as relations3 } from "drizzle-orm";
997
+ import { boolean as boolean2, pgEnum as pgEnum4, pgTable as pgTable4, text as text4, timestamp as timestamp4, uniqueIndex as uniqueIndex4 } from "drizzle-orm/pg-core";
998
+ var userRoleEnum, developerStatusEnum, users, accounts, sessions, verification, usersRelations;
788
999
  var init_table4 = __esm(() => {
789
1000
  init_table3();
790
- init_table();
791
- gamePlatformEnum = pgEnum3("game_platform", ["web", "godot", "unity"]);
792
- gameBootModeEnum = pgEnum3("game_boot_mode", ["iframe", "module"]);
793
- games = pgTable4("games", {
794
- id: uuid3("id").primaryKey().defaultRandom(),
795
- developerId: text4("developer_id").references(() => users.id, {
796
- onDelete: "set null"
1001
+ userRoleEnum = pgEnum4("user_role", ["admin", "player", "developer"]);
1002
+ developerStatusEnum = pgEnum4("developer_status", ["none", "pending", "approved"]);
1003
+ users = pgTable4("user", {
1004
+ id: text4("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
1005
+ name: text4("name").notNull(),
1006
+ username: text4("username").unique(),
1007
+ email: text4("email").notNull().unique(),
1008
+ emailVerified: boolean2("email_verified").notNull().default(false),
1009
+ image: text4("image"),
1010
+ role: userRoleEnum("role").notNull().default("player"),
1011
+ developerStatus: developerStatusEnum("developer_status").notNull().default("none"),
1012
+ characterCreated: boolean2("character_created").notNull().default(false),
1013
+ createdAt: timestamp4("created_at", {
1014
+ mode: "date",
1015
+ withTimezone: true
1016
+ }).notNull(),
1017
+ updatedAt: timestamp4("updated_at", {
1018
+ mode: "date",
1019
+ withTimezone: true
1020
+ }).notNull()
1021
+ });
1022
+ accounts = pgTable4("account", {
1023
+ id: text4("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
1024
+ userId: text4("userId").notNull().references(() => users.id, { onDelete: "cascade" }),
1025
+ accountId: text4("account_id").notNull(),
1026
+ providerId: text4("provider_id").notNull(),
1027
+ accessToken: text4("access_token"),
1028
+ refreshToken: text4("refresh_token"),
1029
+ idToken: text4("id_token"),
1030
+ accessTokenExpiresAt: timestamp4("access_token_expires_at", {
1031
+ mode: "date",
1032
+ withTimezone: true
797
1033
  }),
798
- slug: varchar3("slug", { length: 255 }).notNull().unique(),
799
- displayName: varchar3("display_name", { length: 255 }).notNull(),
800
- version: varchar3("version", { length: 50 }).notNull(),
801
- assetBundleBase: text4("asset_bundle_base").notNull(),
802
- platform: gamePlatformEnum("platform").notNull().default("web"),
803
- mapElementId: uuid3("map_element_id").references(() => mapElements.id, {
804
- onDelete: "set null"
1034
+ refreshTokenExpiresAt: timestamp4("refresh_token_expires_at", {
1035
+ mode: "date",
1036
+ withTimezone: true
805
1037
  }),
806
- metadata: jsonb2("metadata").default("{}"),
807
- createdAt: timestamp3("created_at", { withTimezone: true }).defaultNow(),
808
- updatedAt: timestamp3("updated_at", { withTimezone: true }).defaultNow()
809
- });
810
- gameSessions = pgTable4("game_sessions", {
811
- id: uuid3("id").primaryKey().defaultRandom(),
1038
+ scope: text4("scope"),
1039
+ password: text4("password"),
1040
+ createdAt: timestamp4("created_at", {
1041
+ mode: "date",
1042
+ withTimezone: true
1043
+ }).notNull(),
1044
+ updatedAt: timestamp4("updated_at", {
1045
+ mode: "date",
1046
+ withTimezone: true
1047
+ }).notNull()
1048
+ }, (table) => [uniqueIndex4("account_provider_providerId_idx").on(table.accountId, table.providerId)]);
1049
+ sessions = pgTable4("session", {
1050
+ id: text4("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
812
1051
  userId: text4("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
813
- gameId: uuid3("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
814
- startedAt: timestamp3("started_at", { withTimezone: true }).notNull().defaultNow(),
815
- endedAt: timestamp3("ended_at", { withTimezone: true })
1052
+ expiresAt: timestamp4("expires_at", {
1053
+ mode: "date",
1054
+ withTimezone: true
1055
+ }).notNull(),
1056
+ token: text4("token").notNull().unique(),
1057
+ ipAddress: text4("ip_address"),
1058
+ userAgent: text4("user_agent"),
1059
+ createdAt: timestamp4("created_at", {
1060
+ mode: "date",
1061
+ withTimezone: true
1062
+ }).notNull(),
1063
+ updatedAt: timestamp4("updated_at", {
1064
+ mode: "date",
1065
+ withTimezone: true
1066
+ }).notNull()
816
1067
  });
817
- gameStates = pgTable4("game_states", {
818
- userId: text4("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
819
- gameId: uuid3("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
820
- data: jsonb2("data").default("{}"),
821
- updatedAt: timestamp3("updated_at", { withTimezone: true }).defaultNow()
822
- }, (table) => [uniqueIndex3("unique_user_game_idx").on(table.userId, table.gameId)]);
1068
+ verification = pgTable4("verification", {
1069
+ id: text4("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
1070
+ identifier: text4("identifier").notNull(),
1071
+ value: text4("value").notNull(),
1072
+ expiresAt: timestamp4("expires_at", {
1073
+ mode: "date",
1074
+ withTimezone: true
1075
+ }).notNull(),
1076
+ createdAt: timestamp4("created_at", {
1077
+ mode: "date",
1078
+ withTimezone: true
1079
+ }).notNull(),
1080
+ updatedAt: timestamp4("updated_at", {
1081
+ mode: "date",
1082
+ withTimezone: true
1083
+ }).notNull()
1084
+ });
1085
+ usersRelations = relations3(users, ({ many }) => ({
1086
+ mapObjects: many(mapObjects)
1087
+ }));
823
1088
  });
824
1089
 
825
- // ../data/src/domains/inventory/table.ts
826
- import { relations as relations2, sql } from "drizzle-orm";
827
- import {
828
- boolean as boolean2,
829
- integer,
830
- jsonb as jsonb3,
831
- pgEnum as pgEnum4,
832
- pgTable as pgTable5,
833
- text as text5,
834
- timestamp as timestamp4,
835
- uniqueIndex as uniqueIndex4,
836
- uuid as uuid4
837
- } from "drizzle-orm/pg-core";
838
- var itemTypeEnum, items, inventoryItems, currencies, shopListings, itemsRelations, currenciesRelations, shopListingsRelations, inventoryItemsRelations;
1090
+ // ../data/src/domains/developer/table.ts
1091
+ import { pgTable as pgTable5, text as text5, timestamp as timestamp5, uuid as uuid4, varchar as varchar3 } from "drizzle-orm/pg-core";
1092
+ var developerKeys;
839
1093
  var init_table5 = __esm(() => {
840
1094
  init_table4();
841
- init_table();
842
- itemTypeEnum = pgEnum4("item_type", [
843
- "currency",
844
- "badge",
845
- "trophy",
846
- "collectible",
847
- "consumable",
848
- "unlock",
849
- "upgrade",
850
- "other"
851
- ]);
852
- items = pgTable5("items", {
853
- id: uuid4("id").primaryKey().defaultRandom(),
854
- slug: text5("slug").notNull(),
855
- gameId: uuid4("game_id").references(() => games.id, {
856
- onDelete: "cascade"
857
- }),
858
- displayName: text5("display_name").notNull(),
859
- description: text5("description"),
860
- type: itemTypeEnum("type").notNull().default("other"),
861
- imageUrl: text5("image_url"),
862
- metadata: jsonb3("metadata").default({}),
863
- createdAt: timestamp4("created_at").defaultNow().notNull()
864
- }, (table) => [
865
- uniqueIndex4("items_game_slug_idx").on(table.gameId, table.slug),
866
- uniqueIndex4("items_global_slug_idx").on(table.slug).where(sql`game_id IS NULL`)
867
- ]);
868
- inventoryItems = pgTable5("inventory_items", {
1095
+ developerKeys = pgTable5("developer_keys", {
869
1096
  id: uuid4("id").primaryKey().defaultRandom(),
870
1097
  userId: text5("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
871
- itemId: uuid4("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
872
- quantity: integer("quantity").notNull().default(1),
873
- updatedAt: timestamp4("updated_at", { withTimezone: true }).defaultNow()
874
- }, (table) => [uniqueIndex4("unique_user_item_idx").on(table.userId, table.itemId)]);
875
- currencies = pgTable5("currencies", {
876
- id: uuid4("id").primaryKey().defaultRandom(),
877
- itemId: uuid4("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
878
- symbol: text5("symbol"),
879
- isPrimary: boolean2("is_primary").default(false).notNull(),
880
- createdAt: timestamp4("created_at").defaultNow().notNull(),
881
- updatedAt: timestamp4("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
882
- }, (table) => [uniqueIndex4("currency_item_id_idx").on(table.itemId)]);
883
- shopListings = pgTable5("shop_listings", {
884
- id: uuid4("id").primaryKey().defaultRandom(),
885
- itemId: uuid4("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
886
- currencyId: uuid4("currency_id").notNull().references(() => currencies.id, { onDelete: "restrict" }),
887
- price: integer("price").notNull(),
888
- sellBackPercentage: integer("sell_back_percentage"),
889
- stock: integer("stock"),
890
- isActive: boolean2("is_active").default(true).notNull(),
891
- availableFrom: timestamp4("available_from", { withTimezone: true }),
892
- availableUntil: timestamp4("available_until", { withTimezone: true }),
893
- createdAt: timestamp4("created_at").defaultNow().notNull(),
894
- updatedAt: timestamp4("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
895
- }, (table) => [uniqueIndex4("unique_item_currency_listing_idx").on(table.itemId, table.currencyId)]);
896
- itemsRelations = relations2(items, ({ many }) => ({
897
- shopListings: many(shopListings),
898
- inventoryItems: many(inventoryItems)
899
- }));
900
- currenciesRelations = relations2(currencies, ({ many }) => ({
901
- shopListings: many(shopListings)
902
- }));
903
- shopListingsRelations = relations2(shopListings, ({ one }) => ({
904
- item: one(items, {
905
- fields: [shopListings.itemId],
906
- references: [items.id]
907
- }),
908
- currency: one(currencies, {
909
- fields: [shopListings.currencyId],
910
- references: [currencies.id]
911
- })
912
- }));
913
- inventoryItemsRelations = relations2(inventoryItems, ({ one }) => ({
914
- item: one(items, {
915
- fields: [inventoryItems.itemId],
916
- references: [items.id]
917
- }),
918
- user: one(users, {
919
- fields: [inventoryItems.userId],
920
- references: [users.id]
921
- })
922
- }));
1098
+ label: varchar3("label", { length: 255 }),
1099
+ keyHash: text5("key_hash").notNull().unique(),
1100
+ createdAt: timestamp5("created_at", { withTimezone: true }).notNull().defaultNow()
1101
+ });
923
1102
  });
924
1103
 
925
1104
  // ../data/src/domains/level/table.ts
926
- import { relations as relations3 } from "drizzle-orm";
927
- import { integer as integer2, pgTable as pgTable6, text as text6, timestamp as timestamp5, uniqueIndex as uniqueIndex5, uuid as uuid5 } from "drizzle-orm/pg-core";
1105
+ import { relations as relations4 } from "drizzle-orm";
1106
+ import { integer as integer3, pgTable as pgTable6, text as text6, timestamp as timestamp6, uniqueIndex as uniqueIndex5, uuid as uuid5 } from "drizzle-orm/pg-core";
928
1107
  var userLevels, levelConfigs, userLevelsRelations;
929
1108
  var init_table6 = __esm(() => {
930
- init_table();
1109
+ init_table4();
931
1110
  userLevels = pgTable6("user_levels", {
932
1111
  userId: text6("user_id").primaryKey().references(() => users.id, { onDelete: "cascade" }),
933
- currentLevel: integer2("current_level").notNull().default(1),
934
- currentXp: integer2("current_xp").notNull().default(0),
935
- totalXP: integer2("total_xp").notNull().default(0),
936
- lastLevelUpAt: timestamp5("last_level_up_at", { withTimezone: true }),
937
- createdAt: timestamp5("created_at").defaultNow().notNull(),
938
- updatedAt: timestamp5("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
1112
+ currentLevel: integer3("current_level").notNull().default(1),
1113
+ currentXp: integer3("current_xp").notNull().default(0),
1114
+ totalXP: integer3("total_xp").notNull().default(0),
1115
+ lastLevelUpAt: timestamp6("last_level_up_at", { withTimezone: true }),
1116
+ createdAt: timestamp6("created_at").defaultNow().notNull(),
1117
+ updatedAt: timestamp6("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
939
1118
  });
940
1119
  levelConfigs = pgTable6("level_configs", {
941
1120
  id: uuid5("id").primaryKey().defaultRandom(),
942
- level: integer2("level").notNull().unique(),
943
- xpRequired: integer2("xp_required").notNull(),
944
- creditsReward: integer2("credits_reward").notNull().default(0),
945
- createdAt: timestamp5("created_at").defaultNow().notNull()
1121
+ level: integer3("level").notNull().unique(),
1122
+ xpRequired: integer3("xp_required").notNull(),
1123
+ creditsReward: integer3("credits_reward").notNull().default(0),
1124
+ createdAt: timestamp6("created_at").defaultNow().notNull()
946
1125
  }, (table) => [uniqueIndex5("unique_level_config_idx").on(table.level)]);
947
- userLevelsRelations = relations3(userLevels, ({ one }) => ({
1126
+ userLevelsRelations = relations4(userLevels, ({ one }) => ({
948
1127
  user: one(users, {
949
1128
  fields: [userLevels.userId],
950
1129
  references: [users.id]
@@ -952,14 +1131,158 @@ var init_table6 = __esm(() => {
952
1131
  }));
953
1132
  });
954
1133
 
1134
+ // ../data/src/domains/leaderboard/table.ts
1135
+ import { relations as relations5 } from "drizzle-orm";
1136
+ import { index as index2, integer as integer4, jsonb as jsonb4, pgTable as pgTable7, text as text7, timestamp as timestamp7, uuid as uuid6 } from "drizzle-orm/pg-core";
1137
+ var gameScores, gameScoresRelations;
1138
+ var init_table7 = __esm(() => {
1139
+ init_table();
1140
+ init_table4();
1141
+ gameScores = pgTable7("game_scores", {
1142
+ id: uuid6("id").primaryKey().defaultRandom(),
1143
+ userId: text7("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
1144
+ gameId: uuid6("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
1145
+ score: integer4("score").notNull(),
1146
+ metadata: jsonb4("metadata").default("{}"),
1147
+ achievedAt: timestamp7("achieved_at", { withTimezone: true }).defaultNow().notNull(),
1148
+ sessionId: uuid6("session_id").references(() => gameSessions.id, { onDelete: "set null" })
1149
+ }, (table) => [
1150
+ index2("game_scores_user_game_idx").on(table.userId, table.gameId),
1151
+ index2("game_scores_game_score_idx").on(table.gameId, table.score),
1152
+ index2("game_scores_achieved_at_idx").on(table.achievedAt)
1153
+ ]);
1154
+ gameScoresRelations = relations5(gameScores, ({ one }) => ({
1155
+ user: one(users, {
1156
+ fields: [gameScores.userId],
1157
+ references: [users.id]
1158
+ }),
1159
+ game: one(games, {
1160
+ fields: [gameScores.gameId],
1161
+ references: [games.id]
1162
+ }),
1163
+ session: one(gameSessions, {
1164
+ fields: [gameScores.sessionId],
1165
+ references: [gameSessions.id]
1166
+ })
1167
+ }));
1168
+ });
1169
+
1170
+ // ../data/src/domains/sprite/table.ts
1171
+ import { relations as relations6 } from "drizzle-orm";
1172
+ import { integer as integer5, pgTable as pgTable8, timestamp as timestamp8, uuid as uuid7, varchar as varchar4 } from "drizzle-orm/pg-core";
1173
+ var spriteTemplates, spriteSheets, spriteTemplatesRelations, spriteSheetsRelations;
1174
+ var init_table8 = __esm(() => {
1175
+ spriteTemplates = pgTable8("sprite_templates", {
1176
+ id: uuid7("id").primaryKey().defaultRandom(),
1177
+ slug: varchar4("slug", { length: 64 }).notNull().unique(),
1178
+ url: varchar4("url", { length: 255 }).notNull(),
1179
+ createdAt: timestamp8("created_at", { withTimezone: true }).notNull().defaultNow(),
1180
+ updatedAt: timestamp8("updated_at", { withTimezone: true }).notNull().defaultNow()
1181
+ });
1182
+ spriteSheets = pgTable8("sprite_sheets", {
1183
+ id: uuid7("id").primaryKey().defaultRandom(),
1184
+ templateId: uuid7("template_id").notNull().references(() => spriteTemplates.id, { onDelete: "cascade" }),
1185
+ width: integer5("width").notNull(),
1186
+ height: integer5("height").notNull(),
1187
+ url: varchar4("url", { length: 255 }).notNull(),
1188
+ createdAt: timestamp8("created_at", { withTimezone: true }).notNull().defaultNow(),
1189
+ updatedAt: timestamp8("updated_at", { withTimezone: true }).notNull().defaultNow()
1190
+ });
1191
+ spriteTemplatesRelations = relations6(spriteTemplates, ({ many }) => ({
1192
+ sheets: many(spriteSheets)
1193
+ }));
1194
+ spriteSheetsRelations = relations6(spriteSheets, ({ one }) => ({
1195
+ template: one(spriteTemplates, {
1196
+ fields: [spriteSheets.templateId],
1197
+ references: [spriteTemplates.id]
1198
+ })
1199
+ }));
1200
+ });
1201
+
1202
+ // ../data/src/domains/character/table.ts
1203
+ import { relations as relations7 } from "drizzle-orm";
1204
+ import { integer as integer6, pgEnum as pgEnum5, pgTable as pgTable9, text as text8, timestamp as timestamp9, uuid as uuid8, varchar as varchar5 } from "drizzle-orm/pg-core";
1205
+ var characterComponentTypeEnum, characterComponents, playerCharacters, characterComponentsRelations, playerCharactersRelations;
1206
+ var init_table9 = __esm(() => {
1207
+ init_table8();
1208
+ init_table4();
1209
+ characterComponentTypeEnum = pgEnum5("character_component_type", [
1210
+ "body",
1211
+ "outfit",
1212
+ "hairstyle",
1213
+ "eyes",
1214
+ "accessory"
1215
+ ]);
1216
+ characterComponents = pgTable9("character_components", {
1217
+ id: uuid8("id").primaryKey().defaultRandom(),
1218
+ componentType: characterComponentTypeEnum("component_type").notNull(),
1219
+ slug: varchar5("slug", { length: 128 }).notNull().unique(),
1220
+ displayName: varchar5("display_name", { length: 128 }).notNull(),
1221
+ slot: varchar5("slot", { length: 64 }).notNull(),
1222
+ spriteSheetId: uuid8("sprite_sheet_id").notNull().references(() => spriteSheets.id, { onDelete: "cascade" }),
1223
+ unlockLevel: integer6("unlock_level").notNull().default(0),
1224
+ variant: integer6("variant").notNull().default(0),
1225
+ createdAt: timestamp9("created_at", { withTimezone: true }).notNull().defaultNow(),
1226
+ updatedAt: timestamp9("updated_at", { withTimezone: true }).notNull().defaultNow()
1227
+ });
1228
+ playerCharacters = pgTable9("player_characters", {
1229
+ id: uuid8("id").primaryKey().defaultRandom(),
1230
+ userId: text8("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
1231
+ bodyComponentId: uuid8("body_component_id").notNull().references(() => characterComponents.id, { onDelete: "restrict" }),
1232
+ eyesComponentId: uuid8("eyes_component_id").notNull().references(() => characterComponents.id, { onDelete: "restrict" }),
1233
+ hairstyleComponentId: uuid8("hairstyle_component_id").notNull().references(() => characterComponents.id, { onDelete: "restrict" }),
1234
+ outfitComponentId: uuid8("outfit_component_id").notNull().references(() => characterComponents.id, { onDelete: "restrict" }),
1235
+ accessoryComponentId: uuid8("accessory_component_id").references(() => characterComponents.id, {
1236
+ onDelete: "set null"
1237
+ }),
1238
+ createdAt: timestamp9("created_at", { withTimezone: true }).notNull().defaultNow(),
1239
+ updatedAt: timestamp9("updated_at", { withTimezone: true }).notNull().defaultNow()
1240
+ });
1241
+ characterComponentsRelations = relations7(characterComponents, ({ one }) => ({
1242
+ sheet: one(spriteSheets, {
1243
+ fields: [characterComponents.spriteSheetId],
1244
+ references: [spriteSheets.id]
1245
+ })
1246
+ }));
1247
+ playerCharactersRelations = relations7(playerCharacters, ({ one }) => ({
1248
+ user: one(users, {
1249
+ fields: [playerCharacters.userId],
1250
+ references: [users.id]
1251
+ }),
1252
+ body: one(characterComponents, {
1253
+ fields: [playerCharacters.bodyComponentId],
1254
+ references: [characterComponents.id]
1255
+ }),
1256
+ eyes: one(characterComponents, {
1257
+ fields: [playerCharacters.eyesComponentId],
1258
+ references: [characterComponents.id]
1259
+ }),
1260
+ hair: one(characterComponents, {
1261
+ fields: [playerCharacters.hairstyleComponentId],
1262
+ references: [characterComponents.id]
1263
+ }),
1264
+ outfit: one(characterComponents, {
1265
+ fields: [playerCharacters.outfitComponentId],
1266
+ references: [characterComponents.id]
1267
+ }),
1268
+ accessory: one(characterComponents, {
1269
+ fields: [playerCharacters.accessoryComponentId],
1270
+ references: [characterComponents.id]
1271
+ })
1272
+ }));
1273
+ });
1274
+
955
1275
  // ../data/src/tables.index.ts
956
1276
  var init_tables_index = __esm(() => {
957
- init_table();
958
- init_table2();
959
1277
  init_table4();
960
1278
  init_table5();
1279
+ init_table();
1280
+ init_table2();
961
1281
  init_table3();
962
1282
  init_table6();
1283
+ init_table7();
1284
+ init_table8();
1285
+ init_table9();
963
1286
  });
964
1287
 
965
1288
  // ../data/src/constants.ts
@@ -974,7 +1297,10 @@ var init_constants = __esm(() => {
974
1297
  FIRST_GAME_BADGE: "FIRST_GAME_BADGE",
975
1298
  COMMON_SWORD: "COMMON_SWORD",
976
1299
  SMALL_HEALTH_POTION: "SMALL_HEALTH_POTION",
977
- SMALL_BACKPACK: "SMALL_BACKPACK"
1300
+ SMALL_BACKPACK: "SMALL_BACKPACK",
1301
+ LAVA_LAMP: "LAVA_LAMP",
1302
+ BOOMBOX: "BOOMBOX",
1303
+ CABIN_BED: "CABIN_BED"
978
1304
  };
979
1305
  CURRENCIES = {
980
1306
  PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
@@ -1047,6 +1373,123 @@ var init_credits = __esm(() => {
1047
1373
  init_constants();
1048
1374
  });
1049
1375
 
1376
+ // src/core/namespaces/leaderboard.ts
1377
+ function createLeaderboardNamespace(client) {
1378
+ return {
1379
+ fetch: async (options) => {
1380
+ const params = new URLSearchParams({
1381
+ timeframe: options?.timeframe || "all_time",
1382
+ limit: String(options?.limit || 10),
1383
+ offset: String(options?.offset || 0)
1384
+ });
1385
+ if (options?.gameId) {
1386
+ params.append("gameId", options.gameId);
1387
+ }
1388
+ return client["request"](`/leaderboard?${params}`, "GET");
1389
+ },
1390
+ getUserRank: async (gameId, userId) => {
1391
+ return client["request"](`/games/${gameId}/users/${userId}/rank`, "GET");
1392
+ }
1393
+ };
1394
+ }
1395
+
1396
+ // src/core/namespaces/scores.ts
1397
+ function createScoresNamespace(client) {
1398
+ return {
1399
+ submit: async (gameId, score, metadata) => {
1400
+ return client["request"](`/games/${gameId}/scores`, "POST", {
1401
+ score,
1402
+ metadata
1403
+ });
1404
+ },
1405
+ getByUser: async (gameId, userId, options) => {
1406
+ const params = new URLSearchParams;
1407
+ if (options?.limit) {
1408
+ params.append("limit", String(options.limit));
1409
+ }
1410
+ const queryString = params.toString();
1411
+ const path = queryString ? `/games/${gameId}/users/${userId}/scores?${queryString}` : `/games/${gameId}/users/${userId}/scores`;
1412
+ return client["request"](path, "GET");
1413
+ }
1414
+ };
1415
+ }
1416
+
1417
+ // src/core/namespaces/character.ts
1418
+ function createCharacterNamespace(client) {
1419
+ const componentCache = {};
1420
+ const clearComponentCache = () => {
1421
+ Object.keys(componentCache).forEach((key) => delete componentCache[key]);
1422
+ };
1423
+ const getCachedComponentLevels = () => {
1424
+ return Object.keys(componentCache);
1425
+ };
1426
+ return {
1427
+ get: async (userId) => {
1428
+ try {
1429
+ const path = userId ? `/character/${userId}` : "/character";
1430
+ return await client["request"](path, "GET");
1431
+ } catch (error) {
1432
+ if (error instanceof Error) {
1433
+ if (error.message.includes("404")) {
1434
+ return null;
1435
+ }
1436
+ }
1437
+ throw error;
1438
+ }
1439
+ },
1440
+ create: async (characterData) => {
1441
+ return client["request"]("/character", "POST", characterData);
1442
+ },
1443
+ update: async (updates) => {
1444
+ return client["request"]("/character", "PATCH", updates);
1445
+ },
1446
+ components: {
1447
+ list: async (options) => {
1448
+ const cacheKey = options?.level === undefined ? "all" : String(options.level);
1449
+ if (!options?.skipCache && componentCache[cacheKey]) {
1450
+ return componentCache[cacheKey];
1451
+ }
1452
+ const path = options?.level !== undefined ? `/character/components?level=${options.level}` : "/character/components";
1453
+ const components = await client["request"](path, "GET");
1454
+ componentCache[cacheKey] = components || [];
1455
+ return components || [];
1456
+ },
1457
+ clearCache: clearComponentCache,
1458
+ getCacheKeys: getCachedComponentLevels
1459
+ }
1460
+ };
1461
+ }
1462
+
1463
+ // src/core/namespaces/sprites.ts
1464
+ function createSpritesNamespace(client) {
1465
+ return {
1466
+ templates: {
1467
+ get: async (slug) => {
1468
+ const templateMeta = await client["request"](`/sprites/templates/${slug}`, "GET");
1469
+ if (!templateMeta.url) {
1470
+ throw new Error(`Template ${slug} has no URL in database`);
1471
+ }
1472
+ const response = await fetch(templateMeta.url);
1473
+ if (!response.ok) {
1474
+ throw new Error(`Failed to fetch template JSON from ${templateMeta.url}: ${response.statusText}`);
1475
+ }
1476
+ return response.json();
1477
+ }
1478
+ }
1479
+ };
1480
+ }
1481
+
1482
+ // src/core/namespaces/realtime.ts
1483
+ function createRealtimeNamespace(client) {
1484
+ return {
1485
+ token: {
1486
+ get: async () => {
1487
+ return client["request"]("/realtime/token", "POST");
1488
+ }
1489
+ }
1490
+ };
1491
+ }
1492
+
1050
1493
  // src/core/namespaces/index.ts
1051
1494
  var init_namespaces = __esm(() => {
1052
1495
  init_runtime();
@@ -1258,6 +1701,11 @@ var init_client = __esm(() => {
1258
1701
  levels = createLevelsNamespace(this);
1259
1702
  telemetry = createTelemetryNamespace(this);
1260
1703
  credits = createCreditsNamespace(this);
1704
+ leaderboard = createLeaderboardNamespace(this);
1705
+ scores = createScoresNamespace(this);
1706
+ character = createCharacterNamespace(this);
1707
+ sprites = createSpritesNamespace(this);
1708
+ realtime = createRealtimeNamespace(this);
1261
1709
  static init = init;
1262
1710
  static login = login;
1263
1711
  };