@playcademy/sdk 0.0.9 → 0.1.0

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.d.ts CHANGED
@@ -3021,6 +3021,7 @@ type XpHistoryResponse = {
3021
3021
  xp: number;
3022
3022
  }>;
3023
3023
  };
3024
+ type TimebackSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
3024
3025
  type TimebackSetupRequest = {
3025
3026
  gameId: string;
3026
3027
  config: {
@@ -3108,6 +3109,9 @@ type RecordProgressRequest = {
3108
3109
  gameId: string;
3109
3110
  studentId: string;
3110
3111
  progressData: {
3112
+ sensorUrl?: string;
3113
+ subject?: TimebackSubject;
3114
+ appName?: string;
3111
3115
  score?: number;
3112
3116
  totalQuestions?: number;
3113
3117
  correctQuestions?: number;
@@ -3120,9 +3124,6 @@ type RecordProgressRequest = {
3120
3124
  classId?: string;
3121
3125
  courseName?: string;
3122
3126
  studentEmail?: string;
3123
- subject?: 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
3124
- appName?: string;
3125
- sensorUrl?: string;
3126
3127
  };
3127
3128
  };
3128
3129
  type RecordProgressResponse = {
@@ -3133,6 +3134,9 @@ type RecordSessionEndRequest = {
3133
3134
  gameId: string;
3134
3135
  studentId: string;
3135
3136
  sessionData: {
3137
+ sensorUrl?: string;
3138
+ subject?: TimebackSubject;
3139
+ appName?: string;
3136
3140
  activeTimeSeconds: number;
3137
3141
  inactiveTimeSeconds?: number;
3138
3142
  wasteTimeSeconds?: number;
@@ -3141,9 +3145,6 @@ type RecordSessionEndRequest = {
3141
3145
  courseId?: string;
3142
3146
  courseName?: string;
3143
3147
  studentEmail?: string;
3144
- subject?: 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
3145
- appName?: string;
3146
- sensorUrl?: string;
3147
3148
  };
3148
3149
  };
3149
3150
  type RecordSessionEndResponse = {
@@ -3155,6 +3156,9 @@ type AwardXpRequest = {
3155
3156
  studentId: string;
3156
3157
  xpAmount: number;
3157
3158
  metadata: {
3159
+ sensorUrl: string;
3160
+ subject: TimebackSubject;
3161
+ appName: string;
3158
3162
  reason: string;
3159
3163
  activityId?: string;
3160
3164
  activityName?: string;
@@ -3162,9 +3166,6 @@ type AwardXpRequest = {
3162
3166
  courseName?: string;
3163
3167
  studentEmail?: string;
3164
3168
  bonusType?: string;
3165
- subject?: 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
3166
- appName?: string;
3167
- sensorUrl?: string;
3168
3169
  };
3169
3170
  };
3170
3171
  type AwardXpResponse = {
@@ -3263,6 +3264,7 @@ interface BackendDeploymentBundle {
3263
3264
  type TokenType = 'session' | 'apiKey' | 'gameJwt';
3264
3265
  interface ClientConfig {
3265
3266
  baseUrl: string;
3267
+ gameUrl?: string;
3266
3268
  token?: string;
3267
3269
  tokenType?: TokenType;
3268
3270
  gameId?: string;
@@ -3620,7 +3622,8 @@ type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
3620
3622
  * Provides namespaced access to all platform features including games, users, inventory, and more.
3621
3623
  */
3622
3624
  declare class PlaycademyClient {
3623
- private baseUrl;
3625
+ baseUrl: string;
3626
+ gameUrl?: string;
3624
3627
  private authStrategy;
3625
3628
  private gameId?;
3626
3629
  private config;
@@ -3632,7 +3635,7 @@ declare class PlaycademyClient {
3632
3635
  * Creates a new PlaycademyClient instance.
3633
3636
  *
3634
3637
  * @param config - Optional configuration object
3635
- * @param config.baseUrl - Base URL for API requests (defaults to '/api')
3638
+ * @param config.baseUrl - Base URL (e.g., 'https://hub.playcademy.com' or '/'). SDK automatically appends /api
3636
3639
  * @param config.token - Authentication token
3637
3640
  * @param config.tokenType - Optional token type (auto-detected if not provided)
3638
3641
  * @param config.gameId - Game ID for automatic session management
@@ -3642,10 +3645,19 @@ declare class PlaycademyClient {
3642
3645
  /**
3643
3646
  * Gets the effective base URL for API requests.
3644
3647
  * Converts relative URLs to absolute URLs in browser environments.
3648
+ * Note: baseUrl already includes /api suffix from constructor.
3645
3649
  *
3646
- * @returns The complete base URL for API requests
3650
+ * @returns The complete base URL for API requests (with /api suffix)
3647
3651
  */
3648
3652
  getBaseUrl(): string;
3653
+ /**
3654
+ * Gets the effective game backend URL for integration requests.
3655
+ * Throws if gameUrl is not configured.
3656
+ *
3657
+ * @returns The complete game backend URL for API requests (with /api suffix)
3658
+ * @throws PlaycademyError if gameUrl is not set
3659
+ */
3660
+ private getGameBackendUrl;
3649
3661
  /**
3650
3662
  * Simple ping method for testing connectivity.
3651
3663
  *
@@ -3733,7 +3745,7 @@ declare class PlaycademyClient {
3733
3745
  */
3734
3746
  private emit;
3735
3747
  /**
3736
- * Makes an authenticated HTTP request to the API.
3748
+ * Makes an authenticated HTTP request to the platform API.
3737
3749
  *
3738
3750
  * @param path - API endpoint path
3739
3751
  * @param method - HTTP method
@@ -3742,6 +3754,17 @@ declare class PlaycademyClient {
3742
3754
  * @returns Promise resolving to the response data
3743
3755
  */
3744
3756
  protected request<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
3757
+ /**
3758
+ * Makes an authenticated HTTP request to the game's backend Worker.
3759
+ * Uses gameUrl if set, otherwise falls back to platform API.
3760
+ *
3761
+ * @param path - API endpoint path
3762
+ * @param method - HTTP method
3763
+ * @param body - Request body (optional)
3764
+ * @param headers - Additional headers (optional)
3765
+ * @returns Promise resolving to the response data
3766
+ */
3767
+ protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
3745
3768
  /**
3746
3769
  * Ensures a gameId is available, throwing an error if not.
3747
3770
  *
@@ -4088,7 +4111,7 @@ declare class PlaycademyClient {
4088
4111
  }) => Promise<TodayXpResponse>;
4089
4112
  total: () => Promise<TotalXpResponse>;
4090
4113
  history: (options?: {
4091
- startDate? /** TimeBack XP methods (today, total, history) */: string;
4114
+ startDate?: string;
4092
4115
  endDate?: string;
4093
4116
  }) => Promise<XpHistoryResponse>;
4094
4117
  summary: (options?: {
@@ -4180,6 +4203,15 @@ declare class PlaycademyClient {
4180
4203
  }, cacheOptions?: TTLCacheConfig) => Promise<NotificationStats>;
4181
4204
  };
4182
4205
  };
4206
+ /** Backend methods for calling custom game API routes */
4207
+ backend: {
4208
+ get<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
4209
+ post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
4210
+ put<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
4211
+ patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
4212
+ delete<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
4213
+ request<T = unknown>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
4214
+ };
4183
4215
  /** Auto-initializes a PlaycademyClient with context from the environment */
4184
4216
  static init: typeof init;
4185
4217
  /** Authenticates a user with email and password */
package/dist/index.js CHANGED
@@ -11,7 +11,9 @@ var __export = (target, all) => {
11
11
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
12
12
 
13
13
  // ../logger/src/index.ts
14
- var isBrowser = () => {
14
+ var hasProcess = () => {
15
+ return typeof process !== "undefined";
16
+ }, isBrowser = () => {
15
17
  const g = globalThis;
16
18
  return typeof g.window !== "undefined" && typeof g.document !== "undefined";
17
19
  }, colors, shouldUseColor = () => {
@@ -85,7 +87,9 @@ var isBrowser = () => {
85
87
  }
86
88
  return JSON.stringify(logEntry);
87
89
  }, performLog = (level, message, context) => {
88
- if (level === "debug" && false) {}
90
+ if (level === "debug" && hasProcess() && process.env.PLAYCADEMY_EMBEDDED) {
91
+ return;
92
+ }
89
93
  if (isBrowser()) {
90
94
  logInBrowser(level, message, context);
91
95
  } else {
@@ -860,6 +864,22 @@ function createTTLCache(options) {
860
864
  }
861
865
 
862
866
  // src/core/request.ts
867
+ function checkDevWarnings(data) {
868
+ if (!data || typeof data !== "object")
869
+ return;
870
+ const response = data;
871
+ const warningType = response.__playcademyDevWarning;
872
+ if (!warningType)
873
+ return;
874
+ switch (warningType) {
875
+ case "timeback-disabled":
876
+ console.warn("%c⚠️ TimeBack Disabled in Dev", "background: #f59e0b; color: white; padding: 4px 8px; border-radius: 3px; font-weight: bold", `
877
+ ` + (response.__playcademyDevMessage || "TimeBack is disabled in local development"));
878
+ break;
879
+ default:
880
+ console.warn(`[Playcademy Dev Warning] ${warningType}`);
881
+ }
882
+ }
863
883
  async function request({
864
884
  path,
865
885
  baseUrl,
@@ -894,7 +914,9 @@ async function request({
894
914
  const contentType = res.headers.get("content-type") ?? "";
895
915
  if (contentType.includes("application/json")) {
896
916
  try {
897
- return await res.json();
917
+ const parsed = await res.json();
918
+ checkDevWarnings(parsed);
919
+ return parsed;
898
920
  } catch (err) {
899
921
  if (err instanceof SyntaxError)
900
922
  return;
@@ -1185,15 +1207,7 @@ function createDevNamespace(client) {
1185
1207
  throw new Error(`File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`);
1186
1208
  }
1187
1209
  }
1188
- const baseUrl = (() => {
1189
- const anyClient = client;
1190
- try {
1191
- return typeof anyClient.getBaseUrl === "function" ? anyClient.getBaseUrl() : "/api";
1192
- } catch {
1193
- return "/api";
1194
- }
1195
- })();
1196
- const finalizeUrl = baseUrl.replace(/\/$/, "") + "/games/uploads/finalize/";
1210
+ const finalizeUrl = `${client.baseUrl}/games/uploads/finalize/`;
1197
1211
  const authToken = client.getToken();
1198
1212
  const tokenType = client.getTokenType();
1199
1213
  const headers = {
@@ -2751,17 +2765,42 @@ function createAchievementsNamespace(client) {
2751
2765
  }
2752
2766
  var init_achievements = () => {};
2753
2767
 
2768
+ // src/constants.ts
2769
+ var CURRENCIES2, BADGES2, AuthProvider, TIMEBACK_ROUTES;
2770
+ var init_constants2 = __esm(() => {
2771
+ CURRENCIES2 = {
2772
+ PRIMARY: "PLAYCADEMY_CREDITS",
2773
+ XP: "PLAYCADEMY_XP"
2774
+ };
2775
+ BADGES2 = {
2776
+ FOUNDING_MEMBER: "FOUNDING_MEMBER_BADGE",
2777
+ EARLY_ADOPTER: "EARLY_ADOPTER_BADGE",
2778
+ FIRST_GAME: "FIRST_GAME_BADGE"
2779
+ };
2780
+ AuthProvider = {
2781
+ TIMEBACK: "TIMEBACK"
2782
+ };
2783
+ TIMEBACK_ROUTES = {
2784
+ PROGRESS: "/api/integrations/timeback/progress",
2785
+ SESSION_END: "/api/integrations/timeback/session-end",
2786
+ AWARD_XP: "/api/integrations/timeback/award-xp"
2787
+ };
2788
+ });
2789
+
2754
2790
  // src/core/namespaces/timeback.ts
2755
2791
  function createTimebackNamespace(client) {
2756
2792
  return {
2757
2793
  recordProgress: (progressData) => {
2758
- return client["request"]("/api/integrations/timeback/progress", "POST", { progressData });
2794
+ return client["requestGameBackend"](TIMEBACK_ROUTES.PROGRESS, "POST", { progressData });
2759
2795
  },
2760
2796
  recordSessionEnd: (sessionData) => {
2761
- return client["request"]("/api/integrations/timeback/session-end", "POST", { sessionData });
2797
+ return client["requestGameBackend"](TIMEBACK_ROUTES.SESSION_END, "POST", { sessionData });
2762
2798
  },
2763
2799
  awardXP: (xpAmount, metadata) => {
2764
- return client["request"]("/api/integrations/timeback/award-xp", "POST", { xpAmount, metadata });
2800
+ return client["requestGameBackend"](TIMEBACK_ROUTES.AWARD_XP, "POST", {
2801
+ xpAmount,
2802
+ metadata
2803
+ });
2765
2804
  },
2766
2805
  management: {
2767
2806
  setup: (request2) => {
@@ -2822,6 +2861,9 @@ function createTimebackNamespace(client) {
2822
2861
  }
2823
2862
  };
2824
2863
  }
2864
+ var init_timeback = __esm(() => {
2865
+ init_constants2();
2866
+ });
2825
2867
 
2826
2868
  // src/core/namespaces/notifications.ts
2827
2869
  function createNotificationsNamespace(client) {
@@ -2891,6 +2933,33 @@ function createNotificationsNamespace(client) {
2891
2933
  }
2892
2934
  var init_notifications = () => {};
2893
2935
 
2936
+ // src/core/namespaces/backend.ts
2937
+ function createBackendNamespace(client) {
2938
+ function normalizePath(path) {
2939
+ return path.startsWith("/") ? path : `/${path}`;
2940
+ }
2941
+ return {
2942
+ async get(path, headers) {
2943
+ return client["requestGameBackend"](normalizePath(path), "GET", undefined, headers);
2944
+ },
2945
+ async post(path, body, headers) {
2946
+ return client["requestGameBackend"](normalizePath(path), "POST", body, headers);
2947
+ },
2948
+ async put(path, body, headers) {
2949
+ return client["requestGameBackend"](normalizePath(path), "PUT", body, headers);
2950
+ },
2951
+ async patch(path, body, headers) {
2952
+ return client["requestGameBackend"](normalizePath(path), "PATCH", body, headers);
2953
+ },
2954
+ async delete(path, headers) {
2955
+ return client["requestGameBackend"](normalizePath(path), "DELETE", undefined, headers);
2956
+ },
2957
+ async request(path, method, body, headers) {
2958
+ return client["requestGameBackend"](normalizePath(path), method, body, headers);
2959
+ }
2960
+ };
2961
+ }
2962
+
2894
2963
  // src/core/namespaces/index.ts
2895
2964
  var init_namespaces = __esm(() => {
2896
2965
  init_identity();
@@ -2904,6 +2973,7 @@ var init_namespaces = __esm(() => {
2904
2973
  init_sprites();
2905
2974
  init_realtime();
2906
2975
  init_achievements();
2976
+ init_timeback();
2907
2977
  init_notifications();
2908
2978
  });
2909
2979
 
@@ -2933,6 +3003,9 @@ function buildAllowedOrigins(explicit) {
2933
3003
  return ref ? [ref] : [];
2934
3004
  }
2935
3005
  function isOriginAllowed(origin, allowlist) {
3006
+ if (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1") {
3007
+ return true;
3008
+ }
2936
3009
  if (!allowlist || allowlist.length === 0) {
2937
3010
  console.error("[Playcademy SDK] No allowed origins configured. Consider passing allowedParentOrigins explicitly to init().");
2938
3011
  return false;
@@ -2976,7 +3049,8 @@ async function waitForPlaycademyInit(allowedParentOrigins) {
2976
3049
  function createStandaloneConfig() {
2977
3050
  console.warn("[Playcademy SDK] Standalone mode detected, creating mock context for local development");
2978
3051
  const mockConfig = {
2979
- baseUrl: "/api",
3052
+ baseUrl: "http://localhost:4321",
3053
+ gameUrl: "http://localhost:8788",
2980
3054
  token: "mock-game-token-for-local-dev",
2981
3055
  gameId: "mock-game-id-from-template",
2982
3056
  realtimeUrl: undefined
@@ -2995,6 +3069,7 @@ async function init(options) {
2995
3069
  }
2996
3070
  const client = new PlaycademyClient({
2997
3071
  baseUrl: config.baseUrl,
3072
+ gameUrl: config.gameUrl,
2998
3073
  token: config.token,
2999
3074
  gameId: config.gameId,
3000
3075
  autoStartSession: window.self !== window.top
@@ -3072,6 +3147,7 @@ var init_client = __esm(() => {
3072
3147
  init_static();
3073
3148
  PlaycademyClient = class PlaycademyClient {
3074
3149
  baseUrl;
3150
+ gameUrl;
3075
3151
  authStrategy;
3076
3152
  gameId;
3077
3153
  config;
@@ -3080,7 +3156,8 @@ var init_client = __esm(() => {
3080
3156
  authContext;
3081
3157
  initPayload;
3082
3158
  constructor(config) {
3083
- this.baseUrl = config?.baseUrl || "/api";
3159
+ this.baseUrl = config?.baseUrl?.endsWith("/api") ? config.baseUrl : `${config?.baseUrl}/api`;
3160
+ this.gameUrl = config?.gameUrl;
3084
3161
  this.gameId = config?.gameId;
3085
3162
  this.config = config || {};
3086
3163
  this.authStrategy = createAuthStrategy(config?.token ?? null, config?.tokenType);
@@ -3092,6 +3169,15 @@ var init_client = __esm(() => {
3092
3169
  const isBrowser2 = typeof window !== "undefined";
3093
3170
  return isRelative && isBrowser2 ? `${window.location.origin}${this.baseUrl}` : this.baseUrl;
3094
3171
  }
3172
+ getGameBackendUrl() {
3173
+ if (!this.gameUrl) {
3174
+ throw new PlaycademyError("Game backend URL not configured. gameUrl must be set to use game backend features.");
3175
+ }
3176
+ const isRelative = this.gameUrl.startsWith("/");
3177
+ const isBrowser2 = typeof window !== "undefined";
3178
+ const effectiveGameUrl = isRelative && isBrowser2 ? `${window.location.origin}${this.gameUrl}` : this.gameUrl;
3179
+ return `${effectiveGameUrl}/api`;
3180
+ }
3095
3181
  ping() {
3096
3182
  return "pong";
3097
3183
  }
@@ -3136,6 +3222,19 @@ var init_client = __esm(() => {
3136
3222
  extraHeaders: effectiveHeaders
3137
3223
  });
3138
3224
  }
3225
+ async requestGameBackend(path, method, body, headers) {
3226
+ const effectiveHeaders = {
3227
+ ...headers,
3228
+ ...this.authStrategy.getHeaders()
3229
+ };
3230
+ return request({
3231
+ path,
3232
+ method,
3233
+ body,
3234
+ baseUrl: this.getGameBackendUrl(),
3235
+ extraHeaders: effectiveHeaders
3236
+ });
3237
+ }
3139
3238
  _ensureGameId() {
3140
3239
  if (!this.gameId) {
3141
3240
  throw new PlaycademyError("This operation requires a gameId, but none was provided when initializing the client.");
@@ -3185,6 +3284,7 @@ var init_client = __esm(() => {
3185
3284
  realtime = createRealtimeNamespace(this);
3186
3285
  achievements = createAchievementsNamespace(this);
3187
3286
  notifications = createNotificationsNamespace(this);
3287
+ backend = createBackendNamespace(this);
3188
3288
  static init = init;
3189
3289
  static login = login2;
3190
3290
  static identity = identity;
@@ -3194,20 +3294,7 @@ var init_client = __esm(() => {
3194
3294
  // src/index.ts
3195
3295
  init_client();
3196
3296
  init_messaging();
3197
-
3198
- // src/constants.ts
3199
- var CURRENCIES2 = {
3200
- PRIMARY: "PLAYCADEMY_CREDITS",
3201
- XP: "PLAYCADEMY_XP"
3202
- };
3203
- var BADGES2 = {
3204
- FOUNDING_MEMBER: "FOUNDING_MEMBER_BADGE",
3205
- EARLY_ADOPTER: "EARLY_ADOPTER_BADGE",
3206
- FIRST_GAME: "FIRST_GAME_BADGE"
3207
- };
3208
- var AuthProvider = {
3209
- TIMEBACK: "TIMEBACK"
3210
- };
3297
+ init_constants2();
3211
3298
  export {
3212
3299
  messaging,
3213
3300
  PlaycademyClient,
package/dist/types.d.ts CHANGED
@@ -3705,6 +3705,7 @@ type XpHistoryResponse = {
3705
3705
  xp: number;
3706
3706
  }>;
3707
3707
  };
3708
+ type TimebackSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
3708
3709
  type TimebackSetupRequest = {
3709
3710
  gameId: string;
3710
3711
  config: {
@@ -3792,6 +3793,9 @@ type RecordProgressRequest = {
3792
3793
  gameId: string;
3793
3794
  studentId: string;
3794
3795
  progressData: {
3796
+ sensorUrl?: string;
3797
+ subject?: TimebackSubject;
3798
+ appName?: string;
3795
3799
  score?: number;
3796
3800
  totalQuestions?: number;
3797
3801
  correctQuestions?: number;
@@ -3804,9 +3808,6 @@ type RecordProgressRequest = {
3804
3808
  classId?: string;
3805
3809
  courseName?: string;
3806
3810
  studentEmail?: string;
3807
- subject?: 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
3808
- appName?: string;
3809
- sensorUrl?: string;
3810
3811
  };
3811
3812
  };
3812
3813
  type RecordProgressResponse = {
@@ -3817,6 +3818,9 @@ type RecordSessionEndRequest = {
3817
3818
  gameId: string;
3818
3819
  studentId: string;
3819
3820
  sessionData: {
3821
+ sensorUrl?: string;
3822
+ subject?: TimebackSubject;
3823
+ appName?: string;
3820
3824
  activeTimeSeconds: number;
3821
3825
  inactiveTimeSeconds?: number;
3822
3826
  wasteTimeSeconds?: number;
@@ -3825,9 +3829,6 @@ type RecordSessionEndRequest = {
3825
3829
  courseId?: string;
3826
3830
  courseName?: string;
3827
3831
  studentEmail?: string;
3828
- subject?: 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
3829
- appName?: string;
3830
- sensorUrl?: string;
3831
3832
  };
3832
3833
  };
3833
3834
  type RecordSessionEndResponse = {
@@ -3839,6 +3840,9 @@ type AwardXpRequest = {
3839
3840
  studentId: string;
3840
3841
  xpAmount: number;
3841
3842
  metadata: {
3843
+ sensorUrl: string;
3844
+ subject: TimebackSubject;
3845
+ appName: string;
3842
3846
  reason: string;
3843
3847
  activityId?: string;
3844
3848
  activityName?: string;
@@ -3846,9 +3850,6 @@ type AwardXpRequest = {
3846
3850
  courseName?: string;
3847
3851
  studentEmail?: string;
3848
3852
  bonusType?: string;
3849
- subject?: 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
3850
- appName?: string;
3851
- sensorUrl?: string;
3852
3853
  };
3853
3854
  };
3854
3855
  type AwardXpResponse = {
@@ -4295,7 +4296,8 @@ type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
4295
4296
  * Provides namespaced access to all platform features including games, users, inventory, and more.
4296
4297
  */
4297
4298
  declare class PlaycademyClient {
4298
- private baseUrl;
4299
+ baseUrl: string;
4300
+ gameUrl?: string;
4299
4301
  private authStrategy;
4300
4302
  private gameId?;
4301
4303
  private config;
@@ -4307,7 +4309,7 @@ declare class PlaycademyClient {
4307
4309
  * Creates a new PlaycademyClient instance.
4308
4310
  *
4309
4311
  * @param config - Optional configuration object
4310
- * @param config.baseUrl - Base URL for API requests (defaults to '/api')
4312
+ * @param config.baseUrl - Base URL (e.g., 'https://hub.playcademy.com' or '/'). SDK automatically appends /api
4311
4313
  * @param config.token - Authentication token
4312
4314
  * @param config.tokenType - Optional token type (auto-detected if not provided)
4313
4315
  * @param config.gameId - Game ID for automatic session management
@@ -4317,10 +4319,19 @@ declare class PlaycademyClient {
4317
4319
  /**
4318
4320
  * Gets the effective base URL for API requests.
4319
4321
  * Converts relative URLs to absolute URLs in browser environments.
4322
+ * Note: baseUrl already includes /api suffix from constructor.
4320
4323
  *
4321
- * @returns The complete base URL for API requests
4324
+ * @returns The complete base URL for API requests (with /api suffix)
4322
4325
  */
4323
4326
  getBaseUrl(): string;
4327
+ /**
4328
+ * Gets the effective game backend URL for integration requests.
4329
+ * Throws if gameUrl is not configured.
4330
+ *
4331
+ * @returns The complete game backend URL for API requests (with /api suffix)
4332
+ * @throws PlaycademyError if gameUrl is not set
4333
+ */
4334
+ private getGameBackendUrl;
4324
4335
  /**
4325
4336
  * Simple ping method for testing connectivity.
4326
4337
  *
@@ -4408,7 +4419,7 @@ declare class PlaycademyClient {
4408
4419
  */
4409
4420
  private emit;
4410
4421
  /**
4411
- * Makes an authenticated HTTP request to the API.
4422
+ * Makes an authenticated HTTP request to the platform API.
4412
4423
  *
4413
4424
  * @param path - API endpoint path
4414
4425
  * @param method - HTTP method
@@ -4417,6 +4428,17 @@ declare class PlaycademyClient {
4417
4428
  * @returns Promise resolving to the response data
4418
4429
  */
4419
4430
  protected request<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
4431
+ /**
4432
+ * Makes an authenticated HTTP request to the game's backend Worker.
4433
+ * Uses gameUrl if set, otherwise falls back to platform API.
4434
+ *
4435
+ * @param path - API endpoint path
4436
+ * @param method - HTTP method
4437
+ * @param body - Request body (optional)
4438
+ * @param headers - Additional headers (optional)
4439
+ * @returns Promise resolving to the response data
4440
+ */
4441
+ protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
4420
4442
  /**
4421
4443
  * Ensures a gameId is available, throwing an error if not.
4422
4444
  *
@@ -4763,7 +4785,7 @@ declare class PlaycademyClient {
4763
4785
  }) => Promise<TodayXpResponse>;
4764
4786
  total: () => Promise<TotalXpResponse>;
4765
4787
  history: (options?: {
4766
- startDate? /** TimeBack XP methods (today, total, history) */: string;
4788
+ startDate?: string;
4767
4789
  endDate?: string;
4768
4790
  }) => Promise<XpHistoryResponse>;
4769
4791
  summary: (options?: {
@@ -4855,6 +4877,15 @@ declare class PlaycademyClient {
4855
4877
  }, cacheOptions?: TTLCacheConfig) => Promise<NotificationStats>;
4856
4878
  };
4857
4879
  };
4880
+ /** Backend methods for calling custom game API routes */
4881
+ backend: {
4882
+ get<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
4883
+ post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
4884
+ put<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
4885
+ patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
4886
+ delete<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
4887
+ request<T = unknown>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
4888
+ };
4858
4889
  /** Auto-initializes a PlaycademyClient with context from the environment */
4859
4890
  static init: typeof init;
4860
4891
  /** Authenticates a user with email and password */
@@ -4868,6 +4899,7 @@ declare class PlaycademyClient {
4868
4899
  type TokenType = 'session' | 'apiKey' | 'gameJwt';
4869
4900
  interface ClientConfig {
4870
4901
  baseUrl: string;
4902
+ gameUrl?: string;
4871
4903
  token?: string;
4872
4904
  tokenType?: TokenType;
4873
4905
  gameId?: string;
@@ -4875,6 +4907,7 @@ interface ClientConfig {
4875
4907
  }
4876
4908
  interface InitPayload {
4877
4909
  baseUrl: string;
4910
+ gameUrl?: string;
4878
4911
  token: string;
4879
4912
  gameId: string;
4880
4913
  realtimeUrl?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/sdk",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -27,21 +27,21 @@
27
27
  "scripts": {
28
28
  "build": "bun build.js",
29
29
  "lint": "bunx eslint . --fix --ignore-pattern dist",
30
- "bump": "SKIP_TESTS=1 bunx bumpp --no-tag --no-push -c \"chore(@playcademy/sdk): release v%s\"",
31
- "pub": "bun run build && bun run bump && bun publish --access public",
30
+ "pub": "bun publish.ts",
32
31
  "test": "bun test",
33
32
  "test:watch": "bun test --watch",
34
33
  "docs": "typedoc"
35
34
  },
36
35
  "devDependencies": {
37
- "playcademy": "0.4.0",
38
- "@playcademy/timeback": "0.0.1",
39
- "@playcademy/utils": "0.0.1",
36
+ "@inquirer/prompts": "^7.8.6",
40
37
  "@playcademy/data": "0.0.1",
41
38
  "@playcademy/logger": "0.0.1",
42
39
  "@playcademy/sandbox": "0.1.0-beta.20",
43
40
  "@playcademy/test": "0.0.1",
41
+ "@playcademy/timeback": "0.0.1",
42
+ "@playcademy/utils": "0.0.1",
44
43
  "@types/bun": "latest",
44
+ "playcademy": "0.10.0",
45
45
  "rollup": "^4.50.2",
46
46
  "rollup-plugin-dts": "^6.2.3",
47
47
  "typescript": "^5.7.2",