@playcademy/sdk 0.9.1-beta.2 → 0.9.1-beta.3
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/README.md +109 -602
- package/dist/index.d.ts +19 -1068
- package/dist/index.js +110 -754
- package/dist/internal.d.ts +2021 -7090
- package/dist/internal.js +171 -1163
- package/dist/server/edge.d.ts +9 -359
- package/dist/server.d.ts +9 -359
- package/dist/types.d.ts +550 -4692
- package/package.json +2 -3
package/dist/index.js
CHANGED
|
@@ -19,13 +19,11 @@ var MessageEvents;
|
|
|
19
19
|
MessageEvents2["RESUME"] = "PLAYCADEMY_RESUME";
|
|
20
20
|
MessageEvents2["FORCE_EXIT"] = "PLAYCADEMY_FORCE_EXIT";
|
|
21
21
|
MessageEvents2["OVERLAY"] = "PLAYCADEMY_OVERLAY";
|
|
22
|
-
MessageEvents2["CONNECTION_STATE"] = "PLAYCADEMY_CONNECTION_STATE";
|
|
23
22
|
MessageEvents2["READY"] = "PLAYCADEMY_READY";
|
|
24
23
|
MessageEvents2["INIT_ERROR"] = "PLAYCADEMY_INIT_ERROR";
|
|
25
24
|
MessageEvents2["EXIT"] = "PLAYCADEMY_EXIT";
|
|
26
25
|
MessageEvents2["TELEMETRY"] = "PLAYCADEMY_TELEMETRY";
|
|
27
26
|
MessageEvents2["KEY_EVENT"] = "PLAYCADEMY_KEY_EVENT";
|
|
28
|
-
MessageEvents2["DISPLAY_ALERT"] = "PLAYCADEMY_DISPLAY_ALERT";
|
|
29
27
|
MessageEvents2["DEMO_END"] = "PLAYCADEMY_DEMO_END";
|
|
30
28
|
MessageEvents2["AUTH_STATE_CHANGE"] = "PLAYCADEMY_AUTH_STATE_CHANGE";
|
|
31
29
|
MessageEvents2["AUTH_CALLBACK"] = "PLAYCADEMY_AUTH_CALLBACK";
|
|
@@ -87,7 +85,6 @@ class PlaycademyMessaging {
|
|
|
87
85
|
"PLAYCADEMY_EXIT" /* EXIT */,
|
|
88
86
|
"PLAYCADEMY_TELEMETRY" /* TELEMETRY */,
|
|
89
87
|
"PLAYCADEMY_KEY_EVENT" /* KEY_EVENT */,
|
|
90
|
-
"PLAYCADEMY_DISPLAY_ALERT" /* DISPLAY_ALERT */,
|
|
91
88
|
"PLAYCADEMY_DEMO_END" /* DEMO_END */
|
|
92
89
|
];
|
|
93
90
|
const shouldUsePostMessage = isIframe && iframeToParentEvents.includes(eventType);
|
|
@@ -194,7 +191,6 @@ function createStandaloneConfig() {
|
|
|
194
191
|
gameUrl: globalThis.location.origin,
|
|
195
192
|
token: "mock-game-token-for-local-dev",
|
|
196
193
|
gameId: "mock-game-id-from-template",
|
|
197
|
-
realtimeUrl: undefined,
|
|
198
194
|
mode: "standalone"
|
|
199
195
|
};
|
|
200
196
|
globalThis.PLAYCADEMY = mockConfig;
|
|
@@ -213,10 +209,7 @@ async function init(options) {
|
|
|
213
209
|
gameUrl: config.gameUrl,
|
|
214
210
|
token: config.token,
|
|
215
211
|
gameId: config.gameId,
|
|
216
|
-
mode: config.mode
|
|
217
|
-
autoStartSession: globalThis.self !== window.top,
|
|
218
|
-
onDisconnect: options?.onDisconnect,
|
|
219
|
-
enableConnectionMonitoring: options?.enableConnectionMonitoring
|
|
212
|
+
mode: config.mode
|
|
220
213
|
});
|
|
221
214
|
client["initPayload"] = config;
|
|
222
215
|
messaging.listen("PLAYCADEMY_TOKEN_REFRESH" /* TOKEN_REFRESH */, ({ token }) => client.setToken(token));
|
|
@@ -637,6 +630,80 @@ function getOAuthConfig(provider) {
|
|
|
637
630
|
var identity = {
|
|
638
631
|
parseOAuthState
|
|
639
632
|
};
|
|
633
|
+
// src/namespaces/game/backend.ts
|
|
634
|
+
function normalizePath(path) {
|
|
635
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
636
|
+
}
|
|
637
|
+
function createBackendNamespace(client) {
|
|
638
|
+
return {
|
|
639
|
+
async get(path, headers) {
|
|
640
|
+
return client["requestGameBackend"](normalizePath(path), "GET", undefined, headers);
|
|
641
|
+
},
|
|
642
|
+
async post(path, body, headers) {
|
|
643
|
+
return client["requestGameBackend"](normalizePath(path), "POST", body, headers);
|
|
644
|
+
},
|
|
645
|
+
async put(path, body, headers) {
|
|
646
|
+
return client["requestGameBackend"](normalizePath(path), "PUT", body, headers);
|
|
647
|
+
},
|
|
648
|
+
async patch(path, body, headers) {
|
|
649
|
+
return client["requestGameBackend"](normalizePath(path), "PATCH", body, headers);
|
|
650
|
+
},
|
|
651
|
+
async delete(path, headers) {
|
|
652
|
+
return client["requestGameBackend"](normalizePath(path), "DELETE", undefined, headers);
|
|
653
|
+
},
|
|
654
|
+
async request(path, method, body, headers) {
|
|
655
|
+
return client["requestGameBackend"](normalizePath(path), method, body, headers);
|
|
656
|
+
},
|
|
657
|
+
async download(path, method = "GET", body, headers) {
|
|
658
|
+
return client["requestGameBackend"](normalizePath(path), method, body, headers, { raw: true });
|
|
659
|
+
},
|
|
660
|
+
url(pathOrStrings, ...values) {
|
|
661
|
+
if (Array.isArray(pathOrStrings) && "raw" in pathOrStrings) {
|
|
662
|
+
const strings = pathOrStrings;
|
|
663
|
+
const path2 = strings.reduce((acc, str, i) => acc + str + (values[i] != null ? String(values[i]) : ""), "");
|
|
664
|
+
return `${client.gameUrl}/api${path2.startsWith("/") ? path2 : `/${path2}`}`;
|
|
665
|
+
}
|
|
666
|
+
const path = pathOrStrings;
|
|
667
|
+
return `${client.gameUrl}/api${path.startsWith("/") ? path : `/${path}`}`;
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
// src/core/assert.ts
|
|
672
|
+
function assertPlatformMode(client, operation) {
|
|
673
|
+
if (client.mode !== "platform") {
|
|
674
|
+
throw new PlaycademyError(`${operation} requires platform mode (current: ${client.mode}). Check client.mode before calling.`);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function assertDemoMode(client, operation) {
|
|
678
|
+
if (client.mode !== "demo") {
|
|
679
|
+
throw new PlaycademyError(`${operation} requires demo mode (current: ${client.mode}). Check client.mode before calling.`);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// src/namespaces/game/demo.ts
|
|
684
|
+
function createDemoNamespace(client) {
|
|
685
|
+
return {
|
|
686
|
+
profile: {
|
|
687
|
+
get: async () => {
|
|
688
|
+
assertDemoMode(client, "demo.profile.get()");
|
|
689
|
+
return client["request"]("/users/demo-profile", "GET");
|
|
690
|
+
},
|
|
691
|
+
update: async (updates) => {
|
|
692
|
+
assertDemoMode(client, "demo.profile.update()");
|
|
693
|
+
return client["request"]("/users/demo-profile", "PATCH", {
|
|
694
|
+
body: updates
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
end: (score, options) => {
|
|
699
|
+
assertDemoMode(client, "demo.end()");
|
|
700
|
+
messaging.send("PLAYCADEMY_DEMO_END" /* DEMO_END */, {
|
|
701
|
+
score,
|
|
702
|
+
...options
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
}
|
|
640
707
|
// src/core/auth/utils.ts
|
|
641
708
|
function openPopupWindow(url, name = "auth-popup", width = 500, height = 600) {
|
|
642
709
|
const left = window.screenX + (window.outerWidth - width) / 2;
|
|
@@ -941,17 +1008,7 @@ function createRuntimeNamespace(client) {
|
|
|
941
1008
|
}
|
|
942
1009
|
return res;
|
|
943
1010
|
},
|
|
944
|
-
exit:
|
|
945
|
-
if (client["internalClientSessionId"] && client["gameId"]) {
|
|
946
|
-
try {
|
|
947
|
-
await client["_sessionManager"].endSession(client["internalClientSessionId"], client["gameId"]);
|
|
948
|
-
} catch (error) {
|
|
949
|
-
log.error("[Playcademy SDK] Failed to auto-end session:", {
|
|
950
|
-
sessionId: client["internalClientSessionId"],
|
|
951
|
-
error
|
|
952
|
-
});
|
|
953
|
-
}
|
|
954
|
-
}
|
|
1011
|
+
exit: () => {
|
|
955
1012
|
messaging.send("PLAYCADEMY_EXIT" /* EXIT */, undefined);
|
|
956
1013
|
},
|
|
957
1014
|
onInit: (handler) => {
|
|
@@ -1051,401 +1108,6 @@ function createAssetsNamespace(client) {
|
|
|
1051
1108
|
}
|
|
1052
1109
|
};
|
|
1053
1110
|
}
|
|
1054
|
-
// src/namespaces/game/backend.ts
|
|
1055
|
-
function normalizePath(path) {
|
|
1056
|
-
return path.startsWith("/") ? path : `/${path}`;
|
|
1057
|
-
}
|
|
1058
|
-
function createBackendNamespace(client) {
|
|
1059
|
-
return {
|
|
1060
|
-
async get(path, headers) {
|
|
1061
|
-
return client["requestGameBackend"](normalizePath(path), "GET", undefined, headers);
|
|
1062
|
-
},
|
|
1063
|
-
async post(path, body, headers) {
|
|
1064
|
-
return client["requestGameBackend"](normalizePath(path), "POST", body, headers);
|
|
1065
|
-
},
|
|
1066
|
-
async put(path, body, headers) {
|
|
1067
|
-
return client["requestGameBackend"](normalizePath(path), "PUT", body, headers);
|
|
1068
|
-
},
|
|
1069
|
-
async patch(path, body, headers) {
|
|
1070
|
-
return client["requestGameBackend"](normalizePath(path), "PATCH", body, headers);
|
|
1071
|
-
},
|
|
1072
|
-
async delete(path, headers) {
|
|
1073
|
-
return client["requestGameBackend"](normalizePath(path), "DELETE", undefined, headers);
|
|
1074
|
-
},
|
|
1075
|
-
async request(path, method, body, headers) {
|
|
1076
|
-
return client["requestGameBackend"](normalizePath(path), method, body, headers);
|
|
1077
|
-
},
|
|
1078
|
-
async download(path, method = "GET", body, headers) {
|
|
1079
|
-
return client["requestGameBackend"](normalizePath(path), method, body, headers, { raw: true });
|
|
1080
|
-
},
|
|
1081
|
-
url(pathOrStrings, ...values) {
|
|
1082
|
-
if (Array.isArray(pathOrStrings) && "raw" in pathOrStrings) {
|
|
1083
|
-
const strings = pathOrStrings;
|
|
1084
|
-
const path2 = strings.reduce((acc, str, i) => acc + str + (values[i] != null ? String(values[i]) : ""), "");
|
|
1085
|
-
return `${client.gameUrl}/api${path2.startsWith("/") ? path2 : `/${path2}`}`;
|
|
1086
|
-
}
|
|
1087
|
-
const path = pathOrStrings;
|
|
1088
|
-
return `${client.gameUrl}/api${path.startsWith("/") ? path : `/${path}`}`;
|
|
1089
|
-
}
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
// src/namespaces/game/guard.ts
|
|
1093
|
-
function assertPlatformMode(client, operation) {
|
|
1094
|
-
if (client.mode !== "platform") {
|
|
1095
|
-
throw new PlaycademyError(`${operation} requires platform mode (current: ${client.mode}). Check client.mode before calling.`);
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
function assertDemoMode(client, operation) {
|
|
1099
|
-
if (client.mode !== "demo") {
|
|
1100
|
-
throw new PlaycademyError(`${operation} requires demo mode (current: ${client.mode}). Check client.mode before calling.`);
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
// src/namespaces/game/demo.ts
|
|
1105
|
-
function createDemoNamespace(client) {
|
|
1106
|
-
return {
|
|
1107
|
-
profile: {
|
|
1108
|
-
get: async () => {
|
|
1109
|
-
assertDemoMode(client, "demo.profile.get()");
|
|
1110
|
-
return client["request"]("/users/demo-profile", "GET");
|
|
1111
|
-
},
|
|
1112
|
-
update: async (updates) => {
|
|
1113
|
-
assertDemoMode(client, "demo.profile.update()");
|
|
1114
|
-
return client["request"]("/users/demo-profile", "PATCH", {
|
|
1115
|
-
body: updates
|
|
1116
|
-
});
|
|
1117
|
-
}
|
|
1118
|
-
},
|
|
1119
|
-
end: (score, options) => {
|
|
1120
|
-
assertDemoMode(client, "demo.end()");
|
|
1121
|
-
messaging.send("PLAYCADEMY_DEMO_END" /* DEMO_END */, {
|
|
1122
|
-
score,
|
|
1123
|
-
...options
|
|
1124
|
-
});
|
|
1125
|
-
}
|
|
1126
|
-
};
|
|
1127
|
-
}
|
|
1128
|
-
// src/core/cache/permanent-cache.ts
|
|
1129
|
-
function createPermanentCache(keyPrefix) {
|
|
1130
|
-
const cache = new Map;
|
|
1131
|
-
async function get(key, loader) {
|
|
1132
|
-
const fullKey = keyPrefix ? `${keyPrefix}:${key}` : key;
|
|
1133
|
-
const existing = cache.get(fullKey);
|
|
1134
|
-
if (existing) {
|
|
1135
|
-
return existing;
|
|
1136
|
-
}
|
|
1137
|
-
const promise = loader().catch((error) => {
|
|
1138
|
-
cache.delete(fullKey);
|
|
1139
|
-
throw error;
|
|
1140
|
-
});
|
|
1141
|
-
cache.set(fullKey, promise);
|
|
1142
|
-
return promise;
|
|
1143
|
-
}
|
|
1144
|
-
function clear(key) {
|
|
1145
|
-
if (key === undefined) {
|
|
1146
|
-
cache.clear();
|
|
1147
|
-
} else {
|
|
1148
|
-
const fullKey = keyPrefix ? `${keyPrefix}:${key}` : key;
|
|
1149
|
-
cache.delete(fullKey);
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
function has(key) {
|
|
1153
|
-
const fullKey = keyPrefix ? `${keyPrefix}:${key}` : key;
|
|
1154
|
-
return cache.has(fullKey);
|
|
1155
|
-
}
|
|
1156
|
-
function size() {
|
|
1157
|
-
return cache.size;
|
|
1158
|
-
}
|
|
1159
|
-
function keys() {
|
|
1160
|
-
const result = [];
|
|
1161
|
-
const prefixLen = keyPrefix ? keyPrefix.length + 1 : 0;
|
|
1162
|
-
for (const fullKey of cache.keys()) {
|
|
1163
|
-
result.push(fullKey.substring(prefixLen));
|
|
1164
|
-
}
|
|
1165
|
-
return result;
|
|
1166
|
-
}
|
|
1167
|
-
return { get, clear, has, size, keys };
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
// src/namespaces/game/users.ts
|
|
1171
|
-
function createUsersNamespace(client) {
|
|
1172
|
-
const itemIdCache = createPermanentCache("items");
|
|
1173
|
-
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1174
|
-
async function resolveItemId(identifier) {
|
|
1175
|
-
if (UUID_REGEX.test(identifier)) {
|
|
1176
|
-
return identifier;
|
|
1177
|
-
}
|
|
1178
|
-
const gameId = client["gameId"];
|
|
1179
|
-
const cacheKey = gameId ? `${identifier}:${gameId}` : identifier;
|
|
1180
|
-
return itemIdCache.get(cacheKey, async () => {
|
|
1181
|
-
const queryParams = new URLSearchParams({ slug: identifier });
|
|
1182
|
-
if (gameId) {
|
|
1183
|
-
queryParams.append("gameId", gameId);
|
|
1184
|
-
}
|
|
1185
|
-
const item = await client["request"](`/items/resolve?${queryParams.toString()}`, "GET");
|
|
1186
|
-
return item.id;
|
|
1187
|
-
});
|
|
1188
|
-
}
|
|
1189
|
-
return {
|
|
1190
|
-
me: async () => {
|
|
1191
|
-
assertPlatformMode(client, "users.me()");
|
|
1192
|
-
return client["request"]("/users/me", "GET");
|
|
1193
|
-
},
|
|
1194
|
-
inventory: {
|
|
1195
|
-
get: async () => {
|
|
1196
|
-
assertPlatformMode(client, "users.inventory.get()");
|
|
1197
|
-
return client["request"](`/inventory`, "GET");
|
|
1198
|
-
},
|
|
1199
|
-
add: async (identifier, qty) => {
|
|
1200
|
-
assertPlatformMode(client, "users.inventory.add()");
|
|
1201
|
-
const itemId = await resolveItemId(identifier);
|
|
1202
|
-
const res = await client["request"](`/inventory/add`, "POST", { body: { itemId, qty } });
|
|
1203
|
-
client["emit"]("inventoryChange", {
|
|
1204
|
-
itemId,
|
|
1205
|
-
delta: qty,
|
|
1206
|
-
newTotal: res.newTotal
|
|
1207
|
-
});
|
|
1208
|
-
return res;
|
|
1209
|
-
},
|
|
1210
|
-
remove: async (identifier, qty) => {
|
|
1211
|
-
assertPlatformMode(client, "users.inventory.remove()");
|
|
1212
|
-
const itemId = await resolveItemId(identifier);
|
|
1213
|
-
const res = await client["request"](`/inventory/remove`, "POST", { body: { itemId, qty } });
|
|
1214
|
-
client["emit"]("inventoryChange", {
|
|
1215
|
-
itemId,
|
|
1216
|
-
delta: -qty,
|
|
1217
|
-
newTotal: res.newTotal
|
|
1218
|
-
});
|
|
1219
|
-
return res;
|
|
1220
|
-
},
|
|
1221
|
-
quantity: async (identifier) => {
|
|
1222
|
-
assertPlatformMode(client, "users.inventory.quantity()");
|
|
1223
|
-
const itemId = await resolveItemId(identifier);
|
|
1224
|
-
const inventory = await client["request"](`/inventory`, "GET");
|
|
1225
|
-
const item = inventory.find((inv) => inv.item?.id === itemId);
|
|
1226
|
-
return item?.quantity ?? 0;
|
|
1227
|
-
},
|
|
1228
|
-
has: async (identifier, minQuantity = 1) => {
|
|
1229
|
-
assertPlatformMode(client, "users.inventory.has()");
|
|
1230
|
-
const itemId = await resolveItemId(identifier);
|
|
1231
|
-
const inventory = await client["request"](`/inventory`, "GET");
|
|
1232
|
-
const item = inventory.find((inv) => inv.item?.id === itemId);
|
|
1233
|
-
const qty = item?.quantity ?? 0;
|
|
1234
|
-
return qty >= minQuantity;
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
};
|
|
1238
|
-
}
|
|
1239
|
-
// ../constants/src/achievements.ts
|
|
1240
|
-
var ACHIEVEMENT_IDS = {
|
|
1241
|
-
PLAY_ANY_GAME_DAILY: "play_any_game_daily",
|
|
1242
|
-
DAILY_CHEST_OPEN: "daily_chest_open",
|
|
1243
|
-
LEADERBOARD_TOP3_DAILY: "leaderboard_top3_daily",
|
|
1244
|
-
LEADERBOARD_TOP3_WEEKLY: "leaderboard_top3_weekly",
|
|
1245
|
-
FIRST_SCORE_ANY_GAME: "first_score_any_game",
|
|
1246
|
-
PERSONAL_BEST_ANY_GAME: "personal_best_any_game"
|
|
1247
|
-
};
|
|
1248
|
-
var ACHIEVEMENT_DEFINITIONS = [
|
|
1249
|
-
{
|
|
1250
|
-
id: ACHIEVEMENT_IDS.PLAY_ANY_GAME_DAILY,
|
|
1251
|
-
title: "Play any game",
|
|
1252
|
-
description: "Play any arcade game for at least 60 seconds in a single session.",
|
|
1253
|
-
scope: "daily",
|
|
1254
|
-
rewardCredits: 10,
|
|
1255
|
-
limit: 1,
|
|
1256
|
-
completionType: "time_played_session",
|
|
1257
|
-
completionConfig: { minSeconds: 60 },
|
|
1258
|
-
target: { anyArcadeGame: true },
|
|
1259
|
-
active: true
|
|
1260
|
-
},
|
|
1261
|
-
{
|
|
1262
|
-
id: ACHIEVEMENT_IDS.DAILY_CHEST_OPEN,
|
|
1263
|
-
title: "Opened the daily chest",
|
|
1264
|
-
description: "Find the chest on the map and open it to claim your reward.",
|
|
1265
|
-
scope: "daily",
|
|
1266
|
-
rewardCredits: 10,
|
|
1267
|
-
limit: 1,
|
|
1268
|
-
completionType: "interaction",
|
|
1269
|
-
completionConfig: { triggerId: "bunny_chest" },
|
|
1270
|
-
target: { map: "arcade" },
|
|
1271
|
-
active: true
|
|
1272
|
-
},
|
|
1273
|
-
{
|
|
1274
|
-
id: ACHIEVEMENT_IDS.LEADERBOARD_TOP3_DAILY,
|
|
1275
|
-
title: "Daily Champion",
|
|
1276
|
-
description: "Finish in the top 3 of any game leaderboard for the day.",
|
|
1277
|
-
scope: "daily",
|
|
1278
|
-
rewardCredits: 25,
|
|
1279
|
-
limit: 1,
|
|
1280
|
-
completionType: "leaderboard_rank",
|
|
1281
|
-
completionConfig: {
|
|
1282
|
-
rankRewards: [50, 30, 15]
|
|
1283
|
-
},
|
|
1284
|
-
target: { anyArcadeGame: true },
|
|
1285
|
-
active: true
|
|
1286
|
-
},
|
|
1287
|
-
{
|
|
1288
|
-
id: ACHIEVEMENT_IDS.LEADERBOARD_TOP3_WEEKLY,
|
|
1289
|
-
title: "Weekly Legend",
|
|
1290
|
-
description: "Finish in the top 3 of any game leaderboard for the week.",
|
|
1291
|
-
scope: "weekly",
|
|
1292
|
-
rewardCredits: 50,
|
|
1293
|
-
limit: 1,
|
|
1294
|
-
completionType: "leaderboard_rank",
|
|
1295
|
-
completionConfig: {
|
|
1296
|
-
rankRewards: [100, 60, 30]
|
|
1297
|
-
},
|
|
1298
|
-
target: { anyArcadeGame: true },
|
|
1299
|
-
active: true
|
|
1300
|
-
},
|
|
1301
|
-
{
|
|
1302
|
-
id: ACHIEVEMENT_IDS.FIRST_SCORE_ANY_GAME,
|
|
1303
|
-
title: "First Score",
|
|
1304
|
-
description: "Submit your first score in any arcade game.",
|
|
1305
|
-
scope: "game",
|
|
1306
|
-
rewardCredits: 5,
|
|
1307
|
-
limit: 1,
|
|
1308
|
-
completionType: "first_score",
|
|
1309
|
-
completionConfig: {},
|
|
1310
|
-
target: { anyArcadeGame: true },
|
|
1311
|
-
active: true
|
|
1312
|
-
},
|
|
1313
|
-
{
|
|
1314
|
-
id: ACHIEVEMENT_IDS.PERSONAL_BEST_ANY_GAME,
|
|
1315
|
-
title: "Personal Best",
|
|
1316
|
-
description: "Beat your personal best score in any arcade game.",
|
|
1317
|
-
scope: "daily",
|
|
1318
|
-
rewardCredits: 5,
|
|
1319
|
-
limit: 3,
|
|
1320
|
-
completionType: "personal_best",
|
|
1321
|
-
completionConfig: {},
|
|
1322
|
-
target: { anyArcadeGame: true },
|
|
1323
|
-
active: true
|
|
1324
|
-
}
|
|
1325
|
-
];
|
|
1326
|
-
// ../constants/src/typescript.ts
|
|
1327
|
-
var TypeScriptPackages = {
|
|
1328
|
-
tsc: "tsc",
|
|
1329
|
-
nativePreview: "@typescript/native-preview",
|
|
1330
|
-
nativePreviewBeta: "@typescript/native-preview@beta"
|
|
1331
|
-
};
|
|
1332
|
-
var TYPESCRIPT_RUNNER = {
|
|
1333
|
-
package: TypeScriptPackages.nativePreviewBeta,
|
|
1334
|
-
bin: "tsgo"
|
|
1335
|
-
};
|
|
1336
|
-
// ../constants/src/overworld.ts
|
|
1337
|
-
var ITEM_SLUGS = {
|
|
1338
|
-
PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
|
|
1339
|
-
PLAYCADEMY_XP: "PLAYCADEMY_XP",
|
|
1340
|
-
FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
|
|
1341
|
-
EARLY_ADOPTER_BADGE: "EARLY_ADOPTER_BADGE",
|
|
1342
|
-
FIRST_GAME_BADGE: "FIRST_GAME_BADGE",
|
|
1343
|
-
COMMON_SWORD: "COMMON_SWORD",
|
|
1344
|
-
SMALL_HEALTH_POTION: "SMALL_HEALTH_POTION",
|
|
1345
|
-
SMALL_BACKPACK: "SMALL_BACKPACK",
|
|
1346
|
-
LAVA_LAMP: "LAVA_LAMP",
|
|
1347
|
-
BOOMBOX: "BOOMBOX",
|
|
1348
|
-
CABIN_BED: "CABIN_BED"
|
|
1349
|
-
};
|
|
1350
|
-
var CURRENCIES = {
|
|
1351
|
-
PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
|
|
1352
|
-
XP: ITEM_SLUGS.PLAYCADEMY_XP
|
|
1353
|
-
};
|
|
1354
|
-
var BADGES = {
|
|
1355
|
-
FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
|
|
1356
|
-
EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
|
|
1357
|
-
FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
|
|
1358
|
-
};
|
|
1359
|
-
// ../constants/src/timeback.ts
|
|
1360
|
-
var TIMEBACK_ROUTES = {
|
|
1361
|
-
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
1362
|
-
GET_XP: "/integrations/timeback/xp",
|
|
1363
|
-
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
1364
|
-
ADVANCE_COURSE: "/integrations/timeback/advance-course"
|
|
1365
|
-
};
|
|
1366
|
-
// src/core/cache/singleton-cache.ts
|
|
1367
|
-
function createSingletonCache() {
|
|
1368
|
-
let cachedValue;
|
|
1369
|
-
let hasValue = false;
|
|
1370
|
-
async function get(loader) {
|
|
1371
|
-
if (hasValue) {
|
|
1372
|
-
return cachedValue;
|
|
1373
|
-
}
|
|
1374
|
-
const value = await loader();
|
|
1375
|
-
cachedValue = value;
|
|
1376
|
-
hasValue = true;
|
|
1377
|
-
return value;
|
|
1378
|
-
}
|
|
1379
|
-
function clear() {
|
|
1380
|
-
cachedValue = undefined;
|
|
1381
|
-
hasValue = false;
|
|
1382
|
-
}
|
|
1383
|
-
function has() {
|
|
1384
|
-
return hasValue;
|
|
1385
|
-
}
|
|
1386
|
-
return { get, clear, has };
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
// src/namespaces/game/credits.ts
|
|
1390
|
-
function createCreditsNamespace(client) {
|
|
1391
|
-
const creditsIdCache = createSingletonCache();
|
|
1392
|
-
async function getCreditsItemId() {
|
|
1393
|
-
return creditsIdCache.get(async () => {
|
|
1394
|
-
const queryParams = new URLSearchParams({ slug: CURRENCIES.PRIMARY });
|
|
1395
|
-
const creditsItem = await client["request"](`/items/resolve?${queryParams.toString()}`, "GET");
|
|
1396
|
-
if (!creditsItem || !creditsItem.id) {
|
|
1397
|
-
throw new Error("Playcademy Credits item not found in catalog");
|
|
1398
|
-
}
|
|
1399
|
-
return creditsItem.id;
|
|
1400
|
-
});
|
|
1401
|
-
}
|
|
1402
|
-
return {
|
|
1403
|
-
balance: async () => {
|
|
1404
|
-
assertPlatformMode(client, "credits.balance()");
|
|
1405
|
-
const inventory = await client["request"]("/inventory", "GET");
|
|
1406
|
-
const primaryCurrencyInventoryItem = inventory.find((item) => item.item?.slug === CURRENCIES.PRIMARY);
|
|
1407
|
-
return primaryCurrencyInventoryItem?.quantity ?? 0;
|
|
1408
|
-
},
|
|
1409
|
-
add: async (amount) => {
|
|
1410
|
-
assertPlatformMode(client, "credits.add()");
|
|
1411
|
-
if (amount <= 0) {
|
|
1412
|
-
throw new Error("Amount must be positive");
|
|
1413
|
-
}
|
|
1414
|
-
const creditsItemId = await getCreditsItemId();
|
|
1415
|
-
const result = await client["request"]("/inventory/add", "POST", {
|
|
1416
|
-
body: {
|
|
1417
|
-
itemId: creditsItemId,
|
|
1418
|
-
qty: amount
|
|
1419
|
-
}
|
|
1420
|
-
});
|
|
1421
|
-
client["emit"]("inventoryChange", {
|
|
1422
|
-
itemId: creditsItemId,
|
|
1423
|
-
delta: amount,
|
|
1424
|
-
newTotal: result.newTotal
|
|
1425
|
-
});
|
|
1426
|
-
return result.newTotal;
|
|
1427
|
-
},
|
|
1428
|
-
spend: async (amount) => {
|
|
1429
|
-
assertPlatformMode(client, "credits.spend()");
|
|
1430
|
-
if (amount <= 0) {
|
|
1431
|
-
throw new Error("Amount must be positive");
|
|
1432
|
-
}
|
|
1433
|
-
const creditsItemId = await getCreditsItemId();
|
|
1434
|
-
const result = await client["request"]("/inventory/remove", "POST", {
|
|
1435
|
-
body: {
|
|
1436
|
-
itemId: creditsItemId,
|
|
1437
|
-
qty: amount
|
|
1438
|
-
}
|
|
1439
|
-
});
|
|
1440
|
-
client["emit"]("inventoryChange", {
|
|
1441
|
-
itemId: creditsItemId,
|
|
1442
|
-
delta: -amount,
|
|
1443
|
-
newTotal: result.newTotal
|
|
1444
|
-
});
|
|
1445
|
-
return result.newTotal;
|
|
1446
|
-
}
|
|
1447
|
-
};
|
|
1448
|
-
}
|
|
1449
1111
|
// src/namespaces/game/scores.ts
|
|
1450
1112
|
function createScoresNamespace(client) {
|
|
1451
1113
|
return {
|
|
@@ -1460,18 +1122,6 @@ function createScoresNamespace(client) {
|
|
|
1460
1122
|
}
|
|
1461
1123
|
};
|
|
1462
1124
|
}
|
|
1463
|
-
// src/namespaces/game/realtime.ts
|
|
1464
|
-
function createRealtimeNamespace(client) {
|
|
1465
|
-
return {
|
|
1466
|
-
token: {
|
|
1467
|
-
get: async () => {
|
|
1468
|
-
assertPlatformMode(client, "realtime.token.get()");
|
|
1469
|
-
const endpoint = client["gameId"] ? `/games/${client["gameId"]}/realtime/token` : "/realtime/token";
|
|
1470
|
-
return client["request"](endpoint, "POST");
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
};
|
|
1474
|
-
}
|
|
1475
1125
|
// src/core/guards.ts
|
|
1476
1126
|
var VALID_GRADES = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
|
|
1477
1127
|
var VALID_SUBJECTS = [
|
|
@@ -1491,7 +1141,13 @@ function isValidGrade(value) {
|
|
|
1491
1141
|
function isValidSubject(value) {
|
|
1492
1142
|
return typeof value === "string" && VALID_SUBJECTS.includes(value);
|
|
1493
1143
|
}
|
|
1494
|
-
|
|
1144
|
+
// ../constants/src/timeback.ts
|
|
1145
|
+
var TIMEBACK_ROUTES = {
|
|
1146
|
+
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
1147
|
+
GET_XP: "/integrations/timeback/xp",
|
|
1148
|
+
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
1149
|
+
ADVANCE_COURSE: "/integrations/timeback/advance-course"
|
|
1150
|
+
};
|
|
1495
1151
|
// src/core/cache/ttl-cache.ts
|
|
1496
1152
|
function createTTLCache(options) {
|
|
1497
1153
|
const cache = new Map;
|
|
@@ -2284,6 +1940,15 @@ function createTimebackNamespace(client) {
|
|
|
2284
1940
|
}
|
|
2285
1941
|
};
|
|
2286
1942
|
}
|
|
1943
|
+
// src/namespaces/game/users.ts
|
|
1944
|
+
function createUsersNamespace(client) {
|
|
1945
|
+
return {
|
|
1946
|
+
me: async () => {
|
|
1947
|
+
assertPlatformMode(client, "users.me()");
|
|
1948
|
+
return client["request"]("/users/me", "GET");
|
|
1949
|
+
}
|
|
1950
|
+
};
|
|
1951
|
+
}
|
|
2287
1952
|
// src/namespaces/platform/leaderboard.ts
|
|
2288
1953
|
async function fetchInternalLeaderboardEntries(client, options) {
|
|
2289
1954
|
const params = new URLSearchParams({
|
|
@@ -2396,231 +2061,6 @@ function createAuthStrategy(token, tokenType) {
|
|
|
2396
2061
|
return new GameJwtAuth(token);
|
|
2397
2062
|
}
|
|
2398
2063
|
|
|
2399
|
-
// src/core/connection/monitor.ts
|
|
2400
|
-
class ConnectionMonitor {
|
|
2401
|
-
state = "online";
|
|
2402
|
-
callbacks = new Set;
|
|
2403
|
-
heartbeatInterval;
|
|
2404
|
-
consecutiveFailures = 0;
|
|
2405
|
-
isMonitoring = false;
|
|
2406
|
-
config;
|
|
2407
|
-
constructor(config) {
|
|
2408
|
-
this.config = {
|
|
2409
|
-
baseUrl: config.baseUrl,
|
|
2410
|
-
heartbeatInterval: config.heartbeatInterval ?? 1e4,
|
|
2411
|
-
heartbeatTimeout: config.heartbeatTimeout ?? 5000,
|
|
2412
|
-
failureThreshold: config.failureThreshold ?? 2,
|
|
2413
|
-
enableHeartbeat: config.enableHeartbeat ?? true,
|
|
2414
|
-
enableOfflineEvents: config.enableOfflineEvents ?? true
|
|
2415
|
-
};
|
|
2416
|
-
this._detectInitialState();
|
|
2417
|
-
}
|
|
2418
|
-
start() {
|
|
2419
|
-
if (this.isMonitoring) {
|
|
2420
|
-
return;
|
|
2421
|
-
}
|
|
2422
|
-
this.isMonitoring = true;
|
|
2423
|
-
if (this.config.enableOfflineEvents && typeof globalThis.window !== "undefined") {
|
|
2424
|
-
globalThis.addEventListener("online", this._handleOnline);
|
|
2425
|
-
globalThis.addEventListener("offline", this._handleOffline);
|
|
2426
|
-
}
|
|
2427
|
-
if (this.config.enableHeartbeat) {
|
|
2428
|
-
this._startHeartbeat();
|
|
2429
|
-
}
|
|
2430
|
-
}
|
|
2431
|
-
stop() {
|
|
2432
|
-
if (!this.isMonitoring) {
|
|
2433
|
-
return;
|
|
2434
|
-
}
|
|
2435
|
-
this.isMonitoring = false;
|
|
2436
|
-
if (typeof globalThis.window !== "undefined") {
|
|
2437
|
-
globalThis.removeEventListener("online", this._handleOnline);
|
|
2438
|
-
globalThis.removeEventListener("offline", this._handleOffline);
|
|
2439
|
-
}
|
|
2440
|
-
if (this.heartbeatInterval) {
|
|
2441
|
-
clearInterval(this.heartbeatInterval);
|
|
2442
|
-
this.heartbeatInterval = undefined;
|
|
2443
|
-
}
|
|
2444
|
-
}
|
|
2445
|
-
onChange(callback) {
|
|
2446
|
-
this.callbacks.add(callback);
|
|
2447
|
-
return () => this.callbacks.delete(callback);
|
|
2448
|
-
}
|
|
2449
|
-
getState() {
|
|
2450
|
-
return this.state;
|
|
2451
|
-
}
|
|
2452
|
-
async checkNow() {
|
|
2453
|
-
await this._performHeartbeat();
|
|
2454
|
-
return this.state;
|
|
2455
|
-
}
|
|
2456
|
-
reportRequestFailure(error) {
|
|
2457
|
-
const isNetworkError = error instanceof TypeError || error instanceof Error && error.message.includes("fetch");
|
|
2458
|
-
if (!isNetworkError) {
|
|
2459
|
-
return;
|
|
2460
|
-
}
|
|
2461
|
-
this.consecutiveFailures++;
|
|
2462
|
-
if (this.consecutiveFailures >= this.config.failureThreshold) {
|
|
2463
|
-
this._setState("degraded", "Multiple consecutive request failures");
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
2466
|
-
reportRequestSuccess() {
|
|
2467
|
-
if (this.consecutiveFailures > 0) {
|
|
2468
|
-
this.consecutiveFailures = 0;
|
|
2469
|
-
if (this.state === "degraded") {
|
|
2470
|
-
this._setState("online", "Requests succeeding again");
|
|
2471
|
-
}
|
|
2472
|
-
}
|
|
2473
|
-
}
|
|
2474
|
-
_detectInitialState() {
|
|
2475
|
-
if (typeof navigator !== "undefined" && !navigator.onLine) {
|
|
2476
|
-
this.state = "offline";
|
|
2477
|
-
}
|
|
2478
|
-
}
|
|
2479
|
-
_handleOnline = () => {
|
|
2480
|
-
this.consecutiveFailures = 0;
|
|
2481
|
-
this._setState("online", "Browser online event");
|
|
2482
|
-
};
|
|
2483
|
-
_handleOffline = () => {
|
|
2484
|
-
this._setState("offline", "Browser offline event");
|
|
2485
|
-
};
|
|
2486
|
-
_startHeartbeat() {
|
|
2487
|
-
this._performHeartbeat();
|
|
2488
|
-
this.heartbeatInterval = setInterval(() => {
|
|
2489
|
-
this._performHeartbeat();
|
|
2490
|
-
}, this.config.heartbeatInterval);
|
|
2491
|
-
}
|
|
2492
|
-
async _performHeartbeat() {
|
|
2493
|
-
if (typeof navigator !== "undefined" && !navigator.onLine) {
|
|
2494
|
-
return;
|
|
2495
|
-
}
|
|
2496
|
-
try {
|
|
2497
|
-
const controller = new AbortController;
|
|
2498
|
-
const timeoutId = setTimeout(() => controller.abort(), this.config.heartbeatTimeout);
|
|
2499
|
-
const response = await fetch(`${this.config.baseUrl}/ping`, {
|
|
2500
|
-
method: "GET",
|
|
2501
|
-
signal: controller.signal,
|
|
2502
|
-
cache: "no-store"
|
|
2503
|
-
});
|
|
2504
|
-
clearTimeout(timeoutId);
|
|
2505
|
-
if (response.ok) {
|
|
2506
|
-
this.consecutiveFailures = 0;
|
|
2507
|
-
if (this.state !== "online") {
|
|
2508
|
-
this._setState("online", "Heartbeat successful");
|
|
2509
|
-
}
|
|
2510
|
-
} else {
|
|
2511
|
-
this._handleHeartbeatFailure("Heartbeat returned non-OK status");
|
|
2512
|
-
}
|
|
2513
|
-
} catch (error) {
|
|
2514
|
-
this._handleHeartbeatFailure(error instanceof Error ? error.message : "Heartbeat failed");
|
|
2515
|
-
}
|
|
2516
|
-
}
|
|
2517
|
-
_handleHeartbeatFailure(reason) {
|
|
2518
|
-
this.consecutiveFailures++;
|
|
2519
|
-
if (this.consecutiveFailures >= this.config.failureThreshold) {
|
|
2520
|
-
if (typeof navigator !== "undefined" && !navigator.onLine) {
|
|
2521
|
-
this._setState("offline", reason);
|
|
2522
|
-
} else {
|
|
2523
|
-
this._setState("degraded", reason);
|
|
2524
|
-
}
|
|
2525
|
-
}
|
|
2526
|
-
}
|
|
2527
|
-
_setState(newState, reason) {
|
|
2528
|
-
if (this.state === newState) {
|
|
2529
|
-
return;
|
|
2530
|
-
}
|
|
2531
|
-
const oldState = this.state;
|
|
2532
|
-
this.state = newState;
|
|
2533
|
-
console.debug(`[ConnectionMonitor] ${oldState} → ${newState}: ${reason}`);
|
|
2534
|
-
this.callbacks.forEach((callback) => {
|
|
2535
|
-
try {
|
|
2536
|
-
callback(newState, reason);
|
|
2537
|
-
} catch (error) {
|
|
2538
|
-
console.error("[ConnectionMonitor] Error in callback:", error);
|
|
2539
|
-
}
|
|
2540
|
-
});
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
// src/core/connection/utils.ts
|
|
2544
|
-
function createDisplayAlert(authContext) {
|
|
2545
|
-
return (message, options) => {
|
|
2546
|
-
if (authContext?.isInIframe && typeof globalThis.window !== "undefined" && globalThis.window.parent !== globalThis.window) {
|
|
2547
|
-
window.parent.postMessage({
|
|
2548
|
-
type: "PLAYCADEMY_DISPLAY_ALERT",
|
|
2549
|
-
message,
|
|
2550
|
-
options
|
|
2551
|
-
}, "*");
|
|
2552
|
-
} else {
|
|
2553
|
-
const prefixMap = { error: "❌", warning: "⚠️", info: "ℹ️" };
|
|
2554
|
-
const prefix = (options?.type && prefixMap[options.type]) ?? "ℹ️";
|
|
2555
|
-
console.log(`${prefix} ${message}`);
|
|
2556
|
-
}
|
|
2557
|
-
};
|
|
2558
|
-
}
|
|
2559
|
-
|
|
2560
|
-
// src/core/connection/manager.ts
|
|
2561
|
-
class ConnectionManager {
|
|
2562
|
-
monitor;
|
|
2563
|
-
authContext;
|
|
2564
|
-
disconnectHandler;
|
|
2565
|
-
connectionChangeCallback;
|
|
2566
|
-
currentState = "online";
|
|
2567
|
-
additionalDisconnectHandlers = new Set;
|
|
2568
|
-
constructor(config) {
|
|
2569
|
-
this.authContext = config.authContext;
|
|
2570
|
-
this.disconnectHandler = config.onDisconnect;
|
|
2571
|
-
this.connectionChangeCallback = config.onConnectionChange;
|
|
2572
|
-
if (config.authContext?.isInIframe) {
|
|
2573
|
-
this._setupPlatformListener();
|
|
2574
|
-
}
|
|
2575
|
-
}
|
|
2576
|
-
getState() {
|
|
2577
|
-
return this.monitor?.getState() ?? this.currentState;
|
|
2578
|
-
}
|
|
2579
|
-
async checkNow() {
|
|
2580
|
-
if (!this.monitor) {
|
|
2581
|
-
return this.currentState;
|
|
2582
|
-
}
|
|
2583
|
-
return await this.monitor.checkNow();
|
|
2584
|
-
}
|
|
2585
|
-
reportRequestSuccess() {
|
|
2586
|
-
this.monitor?.reportRequestSuccess();
|
|
2587
|
-
}
|
|
2588
|
-
reportRequestFailure(error) {
|
|
2589
|
-
this.monitor?.reportRequestFailure(error);
|
|
2590
|
-
}
|
|
2591
|
-
onDisconnect(callback) {
|
|
2592
|
-
this.additionalDisconnectHandlers.add(callback);
|
|
2593
|
-
return () => {
|
|
2594
|
-
this.additionalDisconnectHandlers.delete(callback);
|
|
2595
|
-
};
|
|
2596
|
-
}
|
|
2597
|
-
stop() {
|
|
2598
|
-
this.monitor?.stop();
|
|
2599
|
-
}
|
|
2600
|
-
_setupPlatformListener() {
|
|
2601
|
-
messaging.listen("PLAYCADEMY_CONNECTION_STATE" /* CONNECTION_STATE */, ({ state, reason }) => {
|
|
2602
|
-
this.currentState = state;
|
|
2603
|
-
this._handleConnectionChange(state, reason);
|
|
2604
|
-
});
|
|
2605
|
-
}
|
|
2606
|
-
_handleConnectionChange(state, reason) {
|
|
2607
|
-
this.connectionChangeCallback?.(state, reason);
|
|
2608
|
-
if (state === "offline" || state === "degraded") {
|
|
2609
|
-
const context = {
|
|
2610
|
-
state,
|
|
2611
|
-
reason,
|
|
2612
|
-
timestamp: Date.now(),
|
|
2613
|
-
displayAlert: createDisplayAlert(this.authContext)
|
|
2614
|
-
};
|
|
2615
|
-
if (this.disconnectHandler) {
|
|
2616
|
-
this.disconnectHandler(context);
|
|
2617
|
-
}
|
|
2618
|
-
this.additionalDisconnectHandlers.forEach((handler) => {
|
|
2619
|
-
handler(context);
|
|
2620
|
-
});
|
|
2621
|
-
}
|
|
2622
|
-
}
|
|
2623
|
-
}
|
|
2624
2064
|
// src/core/transport/retry.ts
|
|
2625
2065
|
var RETRY_DELAYS_MS = [500, 1500];
|
|
2626
2066
|
function wait(ms) {
|
|
@@ -2770,15 +2210,9 @@ class PlaycademyBaseClient {
|
|
|
2770
2210
|
gameId;
|
|
2771
2211
|
config;
|
|
2772
2212
|
listeners = {};
|
|
2773
|
-
internalClientSessionId;
|
|
2774
2213
|
authContext;
|
|
2775
2214
|
initPayload;
|
|
2776
|
-
connectionManager;
|
|
2777
2215
|
launchId;
|
|
2778
|
-
_sessionManager = {
|
|
2779
|
-
startSession: async (gameId) => this.request(`/games/${gameId}/sessions`, "POST"),
|
|
2780
|
-
endSession: async (sessionId, gameId) => this.request(`/games/${gameId}/sessions/${sessionId}`, "DELETE")
|
|
2781
|
-
};
|
|
2782
2216
|
constructor(config) {
|
|
2783
2217
|
this.baseUrl = config?.baseUrl?.endsWith("/api") ? config.baseUrl : `${config?.baseUrl}/api`;
|
|
2784
2218
|
this.gameUrl = config?.gameUrl;
|
|
@@ -2788,8 +2222,6 @@ class PlaycademyBaseClient {
|
|
|
2788
2222
|
this.config = config || {};
|
|
2789
2223
|
this.authStrategy = createAuthStrategy(config?.token ?? null, config?.tokenType);
|
|
2790
2224
|
this._detectAuthContext();
|
|
2791
|
-
this._initializeInternalSession().catch(() => {});
|
|
2792
|
-
this._initializeConnectionMonitor();
|
|
2793
2225
|
}
|
|
2794
2226
|
getBaseUrl() {
|
|
2795
2227
|
const isRelative = this.baseUrl.startsWith("/");
|
|
@@ -2827,21 +2259,6 @@ class PlaycademyBaseClient {
|
|
|
2827
2259
|
onAuthChange(callback) {
|
|
2828
2260
|
this.on("authChange", (payload) => callback(payload.token));
|
|
2829
2261
|
}
|
|
2830
|
-
onDisconnect(callback) {
|
|
2831
|
-
if (!this.connectionManager) {
|
|
2832
|
-
return () => {};
|
|
2833
|
-
}
|
|
2834
|
-
return this.connectionManager.onDisconnect(callback);
|
|
2835
|
-
}
|
|
2836
|
-
getConnectionState() {
|
|
2837
|
-
return this.connectionManager?.getState() ?? "unknown";
|
|
2838
|
-
}
|
|
2839
|
-
async checkConnection() {
|
|
2840
|
-
if (!this.connectionManager) {
|
|
2841
|
-
return "unknown";
|
|
2842
|
-
}
|
|
2843
|
-
return await this.connectionManager.checkNow();
|
|
2844
|
-
}
|
|
2845
2262
|
_setAuthContext(context) {
|
|
2846
2263
|
this.authContext = context;
|
|
2847
2264
|
}
|
|
@@ -2871,44 +2288,30 @@ class PlaycademyBaseClient {
|
|
|
2871
2288
|
...this.authStrategy.getHeaders(),
|
|
2872
2289
|
...this.launchId ? { "x-playcademy-launch-id": this.launchId } : {}
|
|
2873
2290
|
};
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
});
|
|
2884
|
-
this.connectionManager?.reportRequestSuccess();
|
|
2885
|
-
return result;
|
|
2886
|
-
} catch (error) {
|
|
2887
|
-
this.connectionManager?.reportRequestFailure(error);
|
|
2888
|
-
throw error;
|
|
2889
|
-
}
|
|
2291
|
+
return request({
|
|
2292
|
+
path,
|
|
2293
|
+
method,
|
|
2294
|
+
body: options?.body,
|
|
2295
|
+
baseUrl: this.baseUrl,
|
|
2296
|
+
extraHeaders: effectiveHeaders,
|
|
2297
|
+
raw: options?.raw,
|
|
2298
|
+
retryPolicy: options?.retryPolicy
|
|
2299
|
+
});
|
|
2890
2300
|
}
|
|
2891
2301
|
async requestGameBackend(path, method, body, headers, options) {
|
|
2892
2302
|
const effectiveHeaders = {
|
|
2893
2303
|
...headers,
|
|
2894
2304
|
...this.authStrategy.getHeaders()
|
|
2895
2305
|
};
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
});
|
|
2906
|
-
this.connectionManager?.reportRequestSuccess();
|
|
2907
|
-
return result;
|
|
2908
|
-
} catch (error) {
|
|
2909
|
-
this.connectionManager?.reportRequestFailure(error);
|
|
2910
|
-
throw error;
|
|
2911
|
-
}
|
|
2306
|
+
return request({
|
|
2307
|
+
path,
|
|
2308
|
+
method,
|
|
2309
|
+
body,
|
|
2310
|
+
baseUrl: this.getGameBackendUrl(),
|
|
2311
|
+
extraHeaders: effectiveHeaders,
|
|
2312
|
+
raw: options?.raw,
|
|
2313
|
+
retryPolicy: options?.retryPolicy
|
|
2314
|
+
});
|
|
2912
2315
|
}
|
|
2913
2316
|
_ensureGameId() {
|
|
2914
2317
|
if (!this.gameId) {
|
|
@@ -2919,49 +2322,6 @@ class PlaycademyBaseClient {
|
|
|
2919
2322
|
_detectAuthContext() {
|
|
2920
2323
|
this.authContext = { isInIframe: isInIframe() };
|
|
2921
2324
|
}
|
|
2922
|
-
_initializeConnectionMonitor() {
|
|
2923
|
-
if (typeof globalThis.window === "undefined") {
|
|
2924
|
-
return;
|
|
2925
|
-
}
|
|
2926
|
-
const isEnabled = this.config.enableConnectionMonitoring ?? true;
|
|
2927
|
-
if (!isEnabled) {
|
|
2928
|
-
return;
|
|
2929
|
-
}
|
|
2930
|
-
try {
|
|
2931
|
-
this.connectionManager = new ConnectionManager({
|
|
2932
|
-
baseUrl: this.baseUrl,
|
|
2933
|
-
authContext: this.authContext,
|
|
2934
|
-
onDisconnect: this.config.onDisconnect,
|
|
2935
|
-
onConnectionChange: (state, reason) => {
|
|
2936
|
-
this.emit("connectionChange", { state, reason });
|
|
2937
|
-
}
|
|
2938
|
-
});
|
|
2939
|
-
} catch (error) {
|
|
2940
|
-
log.error("[Playcademy SDK] Failed to initialize connection manager:", { error });
|
|
2941
|
-
}
|
|
2942
|
-
}
|
|
2943
|
-
async _initializeInternalSession() {
|
|
2944
|
-
if (!this.gameId || this.internalClientSessionId) {
|
|
2945
|
-
return;
|
|
2946
|
-
}
|
|
2947
|
-
const shouldAutoStart = this.config.autoStartSession ?? true;
|
|
2948
|
-
if (!shouldAutoStart) {
|
|
2949
|
-
return;
|
|
2950
|
-
}
|
|
2951
|
-
try {
|
|
2952
|
-
const response = await this._sessionManager.startSession(this.gameId);
|
|
2953
|
-
this.internalClientSessionId = response.sessionId;
|
|
2954
|
-
log.debug("[Playcademy SDK] Auto-started game session", {
|
|
2955
|
-
gameId: this.gameId,
|
|
2956
|
-
sessionId: this.internalClientSessionId
|
|
2957
|
-
});
|
|
2958
|
-
} catch (error) {
|
|
2959
|
-
log.error("[Playcademy SDK] Auto-starting session failed for game", {
|
|
2960
|
-
gameId: this.gameId,
|
|
2961
|
-
error
|
|
2962
|
-
});
|
|
2963
|
-
}
|
|
2964
|
-
}
|
|
2965
2325
|
users = createUsersNamespace(this);
|
|
2966
2326
|
}
|
|
2967
2327
|
|
|
@@ -2970,11 +2330,9 @@ class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
2970
2330
|
identity = createIdentityNamespace(this);
|
|
2971
2331
|
runtime = createRuntimeNamespace(this);
|
|
2972
2332
|
timeback = createTimebackNamespace(this);
|
|
2973
|
-
credits = createCreditsNamespace(this);
|
|
2974
2333
|
scores = createScoresNamespace(this);
|
|
2975
2334
|
leaderboard = createLeaderboardFetchNamespace(this);
|
|
2976
2335
|
demo = createDemoNamespace(this);
|
|
2977
|
-
realtime = createRealtimeNamespace(this);
|
|
2978
2336
|
backend = createBackendNamespace(this);
|
|
2979
2337
|
static init = init;
|
|
2980
2338
|
static login = login;
|
|
@@ -2986,7 +2344,5 @@ export {
|
|
|
2986
2344
|
PlaycademyError,
|
|
2987
2345
|
PlaycademyClient,
|
|
2988
2346
|
MessageEvents,
|
|
2989
|
-
ConnectionMonitor,
|
|
2990
|
-
ConnectionManager,
|
|
2991
2347
|
ApiError
|
|
2992
2348
|
};
|