@playcademy/sdk 0.1.13 → 0.1.14
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 +311 -101
- package/dist/index.js +106 -43
- package/dist/server.d.ts +3 -1
- package/dist/types.d.ts +291 -101
- package/package.json +3 -4
package/dist/index.js
CHANGED
|
@@ -123,9 +123,13 @@ var isBrowser = () => {
|
|
|
123
123
|
return false;
|
|
124
124
|
const minLevel = getMinimumLogLevel();
|
|
125
125
|
return levelPriority[level] >= levelPriority[minLevel];
|
|
126
|
-
}, performLog = (level, message, context) => {
|
|
126
|
+
}, customHandler, performLog = (level, message, context) => {
|
|
127
127
|
if (!shouldLog(level))
|
|
128
128
|
return;
|
|
129
|
+
if (customHandler) {
|
|
130
|
+
customHandler(level, message, context);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
129
133
|
const outputFormat = detectOutputFormat();
|
|
130
134
|
switch (outputFormat) {
|
|
131
135
|
case "browser":
|
|
@@ -278,6 +282,28 @@ function isInIframe() {
|
|
|
278
282
|
}
|
|
279
283
|
|
|
280
284
|
// src/core/errors.ts
|
|
285
|
+
function extractApiErrorInfo(error) {
|
|
286
|
+
if (!(error instanceof ApiError)) {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
const info = {
|
|
290
|
+
status: error.status,
|
|
291
|
+
statusText: error.message
|
|
292
|
+
};
|
|
293
|
+
if (error.details && typeof error.details === "object") {
|
|
294
|
+
const details = error.details;
|
|
295
|
+
if ("error" in details && typeof details.error === "string") {
|
|
296
|
+
info.error = details.error;
|
|
297
|
+
}
|
|
298
|
+
if ("message" in details && typeof details.message === "string") {
|
|
299
|
+
info.message = details.message;
|
|
300
|
+
}
|
|
301
|
+
if (!info.error && !info.message) {
|
|
302
|
+
info.details = error.details;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return info;
|
|
306
|
+
}
|
|
281
307
|
var PlaycademyError, ApiError;
|
|
282
308
|
var init_errors = __esm(() => {
|
|
283
309
|
PlaycademyError = class PlaycademyError extends Error {
|
|
@@ -755,7 +781,7 @@ function createRuntimeNamespace(client) {
|
|
|
755
781
|
const forwardKeys = Array.isArray(playcademyConfig?.forwardKeys) ? playcademyConfig.forwardKeys : ["Escape"];
|
|
756
782
|
const keySet = new Set(forwardKeys.map((k) => k.toLowerCase()));
|
|
757
783
|
const keyListener = (event) => {
|
|
758
|
-
if (keySet.has(event.key
|
|
784
|
+
if (keySet.has(event.key?.toLowerCase() ?? "") || keySet.has(event.code?.toLowerCase() ?? "")) {
|
|
759
785
|
messaging.send("PLAYCADEMY_KEY_EVENT" /* KEY_EVENT */, {
|
|
760
786
|
key: event.key,
|
|
761
787
|
code: event.code,
|
|
@@ -842,7 +868,7 @@ function createRuntimeNamespace(client) {
|
|
|
842
868
|
},
|
|
843
869
|
cdn: {
|
|
844
870
|
url(pathOrStrings, ...values) {
|
|
845
|
-
const
|
|
871
|
+
const gameUrl = client["initPayload"]?.gameUrl;
|
|
846
872
|
let path;
|
|
847
873
|
if (Array.isArray(pathOrStrings) && "raw" in pathOrStrings) {
|
|
848
874
|
const strings = pathOrStrings;
|
|
@@ -852,20 +878,20 @@ function createRuntimeNamespace(client) {
|
|
|
852
878
|
} else {
|
|
853
879
|
path = pathOrStrings;
|
|
854
880
|
}
|
|
855
|
-
if (!
|
|
881
|
+
if (!gameUrl) {
|
|
856
882
|
return path.startsWith("./") ? path : "./" + path;
|
|
857
883
|
}
|
|
858
884
|
const cleanPath = path.startsWith("./") ? path.slice(2) : path;
|
|
859
|
-
return
|
|
885
|
+
return gameUrl + cleanPath;
|
|
860
886
|
},
|
|
861
887
|
fetch: async (path, options) => {
|
|
862
|
-
const
|
|
863
|
-
if (!
|
|
888
|
+
const gameUrl = client["initPayload"]?.gameUrl;
|
|
889
|
+
if (!gameUrl) {
|
|
864
890
|
const relativePath = path.startsWith("./") ? path : "./" + path;
|
|
865
891
|
return fetch(relativePath, options);
|
|
866
892
|
}
|
|
867
893
|
const cleanPath = path.startsWith("./") ? path.slice(2) : path;
|
|
868
|
-
return fetch(
|
|
894
|
+
return fetch(gameUrl + cleanPath, options);
|
|
869
895
|
},
|
|
870
896
|
json: async (path) => {
|
|
871
897
|
const response = await client.runtime.cdn.fetch(path);
|
|
@@ -1047,8 +1073,8 @@ async function request({
|
|
|
1047
1073
|
const rawText = await res.text().catch(() => "");
|
|
1048
1074
|
return rawText && rawText.length > 0 ? rawText : undefined;
|
|
1049
1075
|
}
|
|
1050
|
-
async function fetchManifest(
|
|
1051
|
-
const manifestUrl = `${
|
|
1076
|
+
async function fetchManifest(deploymentUrl) {
|
|
1077
|
+
const manifestUrl = `${deploymentUrl.replace(/\/$/, "")}/playcademy.manifest.json`;
|
|
1052
1078
|
try {
|
|
1053
1079
|
const response = await fetch(manifestUrl);
|
|
1054
1080
|
if (!response.ok) {
|
|
@@ -1086,8 +1112,8 @@ function createGamesNamespace(client) {
|
|
|
1086
1112
|
const promise = client["request"](`/games/${gameIdOrSlug}`, "GET");
|
|
1087
1113
|
return gameFetchCache.get(gameIdOrSlug, async () => {
|
|
1088
1114
|
const baseGameData = await promise;
|
|
1089
|
-
if (baseGameData.gameType === "hosted" && baseGameData.
|
|
1090
|
-
const manifestData = await fetchManifest(baseGameData.
|
|
1115
|
+
if (baseGameData.gameType === "hosted" && baseGameData.deploymentUrl !== null && baseGameData.deploymentUrl !== "") {
|
|
1116
|
+
const manifestData = await fetchManifest(baseGameData.deploymentUrl);
|
|
1091
1117
|
return { ...baseGameData, manifest: manifestData };
|
|
1092
1118
|
}
|
|
1093
1119
|
return baseGameData;
|
|
@@ -1276,22 +1302,28 @@ function createDevNamespace(client) {
|
|
|
1276
1302
|
}
|
|
1277
1303
|
},
|
|
1278
1304
|
games: {
|
|
1279
|
-
deploy: {
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1305
|
+
deploy: async (slug, options) => {
|
|
1306
|
+
const { metadata, file, backend, hooks } = options;
|
|
1307
|
+
hooks?.onEvent?.({ type: "init" });
|
|
1308
|
+
let game;
|
|
1309
|
+
if (metadata) {
|
|
1310
|
+
game = await client["request"](`/games/${slug}`, "PUT", {
|
|
1283
1311
|
body: metadata
|
|
1284
1312
|
});
|
|
1285
|
-
if (metadata.gameType === "external"
|
|
1313
|
+
if (metadata.gameType === "external" && !file && !backend) {
|
|
1286
1314
|
return game;
|
|
1287
1315
|
}
|
|
1316
|
+
}
|
|
1317
|
+
let uploadToken;
|
|
1318
|
+
if (file) {
|
|
1288
1319
|
const fileName = file instanceof File ? file.name : "game.zip";
|
|
1289
1320
|
const initiateResponse = await client["request"]("/games/uploads/initiate/", "POST", {
|
|
1290
1321
|
body: {
|
|
1291
1322
|
fileName,
|
|
1292
|
-
gameId: game
|
|
1323
|
+
gameId: game?.id || slug
|
|
1293
1324
|
}
|
|
1294
1325
|
});
|
|
1326
|
+
uploadToken = initiateResponse.uploadToken;
|
|
1295
1327
|
if (hooks?.onEvent && typeof XMLHttpRequest !== "undefined") {
|
|
1296
1328
|
await new Promise((resolve, reject) => {
|
|
1297
1329
|
const xhr = new XMLHttpRequest;
|
|
@@ -1332,7 +1364,9 @@ function createDevNamespace(client) {
|
|
|
1332
1364
|
throw new Error(`File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`);
|
|
1333
1365
|
}
|
|
1334
1366
|
}
|
|
1335
|
-
|
|
1367
|
+
}
|
|
1368
|
+
if (uploadToken || backend) {
|
|
1369
|
+
const deployUrl = `${client.baseUrl}/games/${slug}/deploy`;
|
|
1336
1370
|
const authToken = client.getToken();
|
|
1337
1371
|
const tokenType = client.getTokenType();
|
|
1338
1372
|
const headers = {
|
|
@@ -1345,25 +1379,33 @@ function createDevNamespace(client) {
|
|
|
1345
1379
|
headers["Authorization"] = `Bearer ${authToken}`;
|
|
1346
1380
|
}
|
|
1347
1381
|
}
|
|
1348
|
-
const
|
|
1382
|
+
const requestBody = {};
|
|
1383
|
+
if (uploadToken)
|
|
1384
|
+
requestBody.uploadToken = uploadToken;
|
|
1385
|
+
if (metadata)
|
|
1386
|
+
requestBody.metadata = metadata;
|
|
1387
|
+
if (backend) {
|
|
1388
|
+
requestBody.code = backend.code;
|
|
1389
|
+
requestBody.config = backend.config;
|
|
1390
|
+
if (backend.bindings)
|
|
1391
|
+
requestBody.bindings = backend.bindings;
|
|
1392
|
+
if (backend.schema)
|
|
1393
|
+
requestBody.schema = backend.schema;
|
|
1394
|
+
if (backend.secrets)
|
|
1395
|
+
requestBody.secrets = backend.secrets;
|
|
1396
|
+
}
|
|
1397
|
+
const finalizeResponse = await fetch(deployUrl, {
|
|
1349
1398
|
method: "POST",
|
|
1350
1399
|
headers,
|
|
1351
|
-
body: JSON.stringify(
|
|
1352
|
-
tempS3Key: initiateResponse.tempS3Key,
|
|
1353
|
-
gameId: initiateResponse.gameId,
|
|
1354
|
-
version: initiateResponse.version,
|
|
1355
|
-
slug,
|
|
1356
|
-
metadata,
|
|
1357
|
-
originalFileName: fileName
|
|
1358
|
-
}),
|
|
1400
|
+
body: JSON.stringify(requestBody),
|
|
1359
1401
|
credentials: "omit"
|
|
1360
1402
|
});
|
|
1361
1403
|
if (!finalizeResponse.ok) {
|
|
1362
1404
|
const errText = await finalizeResponse.text().catch(() => "");
|
|
1363
|
-
throw new Error(`
|
|
1405
|
+
throw new Error(`Deploy request failed: ${finalizeResponse.status} ${finalizeResponse.statusText}${errText ? ` - ${errText}` : ""}`);
|
|
1364
1406
|
}
|
|
1365
1407
|
if (!finalizeResponse.body) {
|
|
1366
|
-
throw new Error("
|
|
1408
|
+
throw new Error("Deploy response body missing");
|
|
1367
1409
|
}
|
|
1368
1410
|
hooks?.onEvent?.({ type: "finalizeStart" });
|
|
1369
1411
|
let sawAnyServerEvent = false;
|
|
@@ -1418,20 +1460,19 @@ function createDevNamespace(client) {
|
|
|
1418
1460
|
}
|
|
1419
1461
|
}
|
|
1420
1462
|
}
|
|
1421
|
-
throw new Error("
|
|
1422
|
-
},
|
|
1423
|
-
backend: async (slug, bundle) => {
|
|
1424
|
-
return client["request"](`/games/${slug}/backend/deploy`, "POST", { body: bundle });
|
|
1425
|
-
},
|
|
1426
|
-
seed: async (slug, code, environment) => {
|
|
1427
|
-
return client["request"](`/games/${slug}/seed`, "POST", {
|
|
1428
|
-
body: { code, environment }
|
|
1429
|
-
});
|
|
1463
|
+
throw new Error("Deployment completed but no final game data received");
|
|
1430
1464
|
}
|
|
1465
|
+
if (game) {
|
|
1466
|
+
return game;
|
|
1467
|
+
}
|
|
1468
|
+
throw new Error("No deployment actions specified (need metadata, file, or backend)");
|
|
1431
1469
|
},
|
|
1432
|
-
|
|
1433
|
-
return client
|
|
1470
|
+
seed: async (slug, code, environment) => {
|
|
1471
|
+
return client["request"](`/games/${slug}/seed`, "POST", {
|
|
1472
|
+
body: { code, environment }
|
|
1473
|
+
});
|
|
1434
1474
|
},
|
|
1475
|
+
upsert: async (slug, metadata) => client["request"](`/games/${slug}`, "PUT", { body: metadata }),
|
|
1435
1476
|
delete: (gameId) => client["request"](`/games/${gameId}`, "DELETE"),
|
|
1436
1477
|
secrets: {
|
|
1437
1478
|
set: async (slug, secrets) => {
|
|
@@ -1488,6 +1529,24 @@ function createDevNamespace(client) {
|
|
|
1488
1529
|
delete: async (slug, key) => {
|
|
1489
1530
|
await client["request"](`/games/${slug}/bucket/${encodeURIComponent(key)}`, "DELETE");
|
|
1490
1531
|
}
|
|
1532
|
+
},
|
|
1533
|
+
domains: {
|
|
1534
|
+
add: async (slug, hostname) => {
|
|
1535
|
+
return client["request"](`/games/${slug}/domains`, "POST", {
|
|
1536
|
+
body: { hostname }
|
|
1537
|
+
});
|
|
1538
|
+
},
|
|
1539
|
+
list: async (slug) => {
|
|
1540
|
+
const result = await client["request"](`/games/${slug}/domains`, "GET");
|
|
1541
|
+
return result.domains;
|
|
1542
|
+
},
|
|
1543
|
+
status: async (slug, hostname, refresh) => {
|
|
1544
|
+
const params = refresh ? "?refresh=true" : "";
|
|
1545
|
+
return client["request"](`/games/${slug}/domains/${hostname}${params}`, "GET");
|
|
1546
|
+
},
|
|
1547
|
+
delete: async (slug, hostname) => {
|
|
1548
|
+
await client["request"](`/games/${slug}/domains/${hostname}`, "DELETE");
|
|
1549
|
+
}
|
|
1491
1550
|
}
|
|
1492
1551
|
},
|
|
1493
1552
|
items: {
|
|
@@ -2537,7 +2596,7 @@ function createStandaloneConfig() {
|
|
|
2537
2596
|
console.warn("[Playcademy SDK] Standalone mode detected, creating mock context for local development");
|
|
2538
2597
|
const mockConfig = {
|
|
2539
2598
|
baseUrl: "http://localhost:4321",
|
|
2540
|
-
gameUrl:
|
|
2599
|
+
gameUrl: window.location.origin,
|
|
2541
2600
|
token: "mock-game-token-for-local-dev",
|
|
2542
2601
|
gameId: "mock-game-id-from-template",
|
|
2543
2602
|
realtimeUrl: undefined
|
|
@@ -2782,9 +2841,13 @@ var init_client = __esm(() => {
|
|
|
2782
2841
|
|
|
2783
2842
|
// src/index.ts
|
|
2784
2843
|
init_client();
|
|
2844
|
+
init_errors();
|
|
2785
2845
|
init_messaging();
|
|
2786
2846
|
export {
|
|
2787
2847
|
messaging,
|
|
2848
|
+
extractApiErrorInfo,
|
|
2849
|
+
PlaycademyError,
|
|
2788
2850
|
PlaycademyClient,
|
|
2789
|
-
MessageEvents
|
|
2851
|
+
MessageEvents,
|
|
2852
|
+
ApiError
|
|
2790
2853
|
};
|
package/dist/server.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ interface IntegrationsConfig {
|
|
|
54
54
|
kv?: boolean;
|
|
55
55
|
/** Bucket storage (optional) */
|
|
56
56
|
bucket?: boolean;
|
|
57
|
+
/** Authentication (optional) */
|
|
58
|
+
auth?: boolean;
|
|
57
59
|
}
|
|
58
60
|
/**
|
|
59
61
|
* Unified Playcademy configuration
|
|
@@ -371,4 +373,4 @@ declare function verifyGameToken(gameToken: string, options?: {
|
|
|
371
373
|
}>;
|
|
372
374
|
|
|
373
375
|
export { PlaycademyClient, verifyGameToken };
|
|
374
|
-
export type { BackendDeploymentBundle, BackendResourceBindings, IntegrationsConfig, PlaycademyConfig, PlaycademyServerClientConfig, PlaycademyServerClientState, TimebackIntegrationConfig };
|
|
376
|
+
export type { BackendDeploymentBundle, BackendResourceBindings, IntegrationsConfig, PlaycademyConfig, PlaycademyServerClientConfig, PlaycademyServerClientState, TimebackIntegrationConfig, UserInfo };
|