@playcademy/sdk 0.0.1-beta.26 → 0.0.1-beta.28
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/core/client.d.ts
CHANGED
|
@@ -98,12 +98,7 @@ export declare class PlaycademyClient {
|
|
|
98
98
|
fetch: (gameIdOrSlug: string) => Promise<import("@playcademy/data/types").GameWithManifest>;
|
|
99
99
|
list: () => Promise<Array<import("@playcademy/data/types").Game>>;
|
|
100
100
|
saveState: (state: Record<string, unknown>) => Promise<void>;
|
|
101
|
-
loadState: () => Promise<
|
|
102
|
-
data: unknown;
|
|
103
|
-
updatedAt: Date | null;
|
|
104
|
-
userId: string;
|
|
105
|
-
gameId: string;
|
|
106
|
-
}>;
|
|
101
|
+
loadState: () => Promise<import("@playcademy/data/types").GameStateData>;
|
|
107
102
|
startSession: (gameId?: string) => Promise<import("../types").StartSessionResponse>;
|
|
108
103
|
endSession: (sessionId: string, gameId?: string) => Promise<void>;
|
|
109
104
|
};
|
|
@@ -176,14 +171,7 @@ export declare class PlaycademyClient {
|
|
|
176
171
|
};
|
|
177
172
|
/** Map methods (elements) */
|
|
178
173
|
maps: {
|
|
179
|
-
elements: (mapId: string) => Promise<
|
|
180
|
-
id: string;
|
|
181
|
-
mapId: string | null;
|
|
182
|
-
elementSlug: string;
|
|
183
|
-
interactionType: "info" | "game_entry" | "game_registry" | "teleport" | "door_in" | "door_out" | "npc_interaction" | "quest_trigger";
|
|
184
|
-
metadata: Record<string, unknown> | null;
|
|
185
|
-
gameId: string | null;
|
|
186
|
-
}[]>;
|
|
174
|
+
elements: (mapId: string) => Promise<import("@playcademy/data/types").MapElementWithGame[]>;
|
|
187
175
|
};
|
|
188
176
|
/** Admin methods (games, items, currencies, shop listings) */
|
|
189
177
|
admin: {
|
|
@@ -55,8 +55,9 @@ export declare function createDevNamespace(client: PlaycademyClient): {
|
|
|
55
55
|
* ```typescript
|
|
56
56
|
* const gameFile = new File([zipData], 'game.zip')
|
|
57
57
|
* const game = await client.dev.games.upsert('my-game', {
|
|
58
|
-
*
|
|
59
|
-
*
|
|
58
|
+
* displayName: 'My Awesome Game',
|
|
59
|
+
* platform: 'web',
|
|
60
|
+
* metadata: { description: 'A fun puzzle game' }
|
|
60
61
|
* }, gameFile)
|
|
61
62
|
* ```
|
|
62
63
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Game, GameWithManifest } from '@playcademy/data/types';
|
|
1
|
+
import type { Game, GameStateData, GameWithManifest } from '@playcademy/data/types';
|
|
2
2
|
import type { PlaycademyClient, StartSessionResponse } from '../../types';
|
|
3
3
|
/**
|
|
4
4
|
* Creates the games namespace for the PlaycademyClient.
|
|
@@ -56,7 +56,7 @@ export declare function createGamesNamespace(client: PlaycademyClient): {
|
|
|
56
56
|
* Loads the saved game state from the server.
|
|
57
57
|
* Requires a gameId to be configured in the client.
|
|
58
58
|
*
|
|
59
|
-
* @returns Promise resolving to the saved game state
|
|
59
|
+
* @returns Promise resolving to the saved game state data
|
|
60
60
|
*
|
|
61
61
|
* @example
|
|
62
62
|
* ```typescript
|
|
@@ -64,12 +64,7 @@ export declare function createGamesNamespace(client: PlaycademyClient): {
|
|
|
64
64
|
* console.log('Current level:', state.level)
|
|
65
65
|
* ```
|
|
66
66
|
*/
|
|
67
|
-
loadState: () => Promise<
|
|
68
|
-
data: unknown;
|
|
69
|
-
updatedAt: Date | null;
|
|
70
|
-
userId: string;
|
|
71
|
-
gameId: string;
|
|
72
|
-
}>;
|
|
67
|
+
loadState: () => Promise<GameStateData>;
|
|
73
68
|
/**
|
|
74
69
|
* Starts a new game session.
|
|
75
70
|
*
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MapElementWithGame } from '@playcademy/data/types';
|
|
1
2
|
import type { PlaycademyClient } from '../../types';
|
|
2
3
|
/**
|
|
3
4
|
* Creates the maps namespace for the PlaycademyClient.
|
|
@@ -11,22 +12,15 @@ export declare function createMapsNamespace(client: PlaycademyClient): {
|
|
|
11
12
|
* Retrieves all elements for a specific map.
|
|
12
13
|
*
|
|
13
14
|
* @param mapId - The ID of the map to get elements for
|
|
14
|
-
* @returns Promise resolving to array of map elements
|
|
15
|
+
* @returns Promise resolving to array of map elements with game data
|
|
15
16
|
*
|
|
16
17
|
* @example
|
|
17
18
|
* ```typescript
|
|
18
19
|
* const elements = await client.maps.elements('map-123')
|
|
19
20
|
* elements.forEach(element => {
|
|
20
|
-
* console.log(`Element: ${element.
|
|
21
|
+
* console.log(`Element: ${element.elementSlug} - Game: ${element.game?.displayName || 'None'}`)
|
|
21
22
|
* })
|
|
22
23
|
* ```
|
|
23
24
|
*/
|
|
24
|
-
elements: (mapId: string) => Promise<
|
|
25
|
-
id: string;
|
|
26
|
-
mapId: string | null;
|
|
27
|
-
elementSlug: string;
|
|
28
|
-
interactionType: "info" | "game_entry" | "game_registry" | "teleport" | "door_in" | "door_out" | "npc_interaction" | "quest_trigger";
|
|
29
|
-
metadata: Record<string, unknown> | null;
|
|
30
|
-
gameId: string | null;
|
|
31
|
-
}[]>;
|
|
25
|
+
elements: (mapId: string) => Promise<MapElementWithGame[]>;
|
|
32
26
|
};
|
package/dist/index.js
CHANGED
|
@@ -268,7 +268,8 @@ async function request({
|
|
|
268
268
|
credentials: "omit"
|
|
269
269
|
});
|
|
270
270
|
if (!res.ok) {
|
|
271
|
-
const
|
|
271
|
+
const clonedRes = res.clone();
|
|
272
|
+
const errorBody = await clonedRes.json().catch(() => clonedRes.text().catch(() => {
|
|
272
273
|
return;
|
|
273
274
|
})) ?? undefined;
|
|
274
275
|
throw new ApiError(res.status, res.statusText, errorBody);
|
|
@@ -389,12 +390,15 @@ function createUsersNamespace(client) {
|
|
|
389
390
|
},
|
|
390
391
|
quantity: async (identifier) => {
|
|
391
392
|
const itemId = await resolveItemId(identifier);
|
|
392
|
-
const inventory = await client
|
|
393
|
+
const inventory = await client["request"](`/inventory`, "GET");
|
|
393
394
|
const item = inventory.find((inv) => inv.item?.id === itemId);
|
|
394
395
|
return item?.quantity ?? 0;
|
|
395
396
|
},
|
|
396
397
|
has: async (identifier, minQuantity = 1) => {
|
|
397
|
-
const
|
|
398
|
+
const itemId = await resolveItemId(identifier);
|
|
399
|
+
const inventory = await client["request"](`/inventory`, "GET");
|
|
400
|
+
const item = inventory.find((inv) => inv.item?.id === itemId);
|
|
401
|
+
const qty = item?.quantity ?? 0;
|
|
398
402
|
return qty >= minQuantity;
|
|
399
403
|
}
|
|
400
404
|
}
|
|
@@ -412,11 +416,63 @@ function createDevNamespace(client) {
|
|
|
412
416
|
}
|
|
413
417
|
},
|
|
414
418
|
games: {
|
|
415
|
-
upsert: (slug, metadata, file) => {
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
419
|
+
upsert: async (slug, metadata, file) => {
|
|
420
|
+
const game = await client["request"](`/games/${slug}`, "PUT", metadata);
|
|
421
|
+
const fileName = file instanceof File ? file.name : "game.zip";
|
|
422
|
+
const initiateResponse = await client["request"]("/games/uploads/initiate/", "POST", {
|
|
423
|
+
fileName,
|
|
424
|
+
gameId: game.id
|
|
425
|
+
});
|
|
426
|
+
const uploadResponse = await fetch(initiateResponse.presignedUrl, {
|
|
427
|
+
method: "PUT",
|
|
428
|
+
body: file,
|
|
429
|
+
headers: {
|
|
430
|
+
"Content-Type": file.type || "application/octet-stream"
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
if (!uploadResponse.ok) {
|
|
434
|
+
throw new Error(`File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`);
|
|
435
|
+
}
|
|
436
|
+
const finalizeResponse = await client["request"]("/games/uploads/finalize/", "POST", {
|
|
437
|
+
tempS3Key: initiateResponse.tempS3Key,
|
|
438
|
+
gameId: initiateResponse.gameId,
|
|
439
|
+
version: initiateResponse.version,
|
|
440
|
+
slug,
|
|
441
|
+
metadata,
|
|
442
|
+
originalFileName: fileName
|
|
443
|
+
});
|
|
444
|
+
if (!finalizeResponse.body) {
|
|
445
|
+
throw new Error("Finalize response body missing");
|
|
446
|
+
}
|
|
447
|
+
const reader = finalizeResponse.body.pipeThrough(new TextDecoderStream).getReader();
|
|
448
|
+
let buffer = "";
|
|
449
|
+
while (true) {
|
|
450
|
+
const { done, value } = await reader.read();
|
|
451
|
+
if (done)
|
|
452
|
+
break;
|
|
453
|
+
buffer += value;
|
|
454
|
+
let eolIndex;
|
|
455
|
+
while ((eolIndex = buffer.indexOf(`
|
|
456
|
+
|
|
457
|
+
`)) >= 0) {
|
|
458
|
+
const message = buffer.slice(0, eolIndex);
|
|
459
|
+
buffer = buffer.slice(eolIndex + 2);
|
|
460
|
+
const eventLine = message.match(/^event: (.*)$/m);
|
|
461
|
+
const dataLine = message.match(/^data: (.*)$/m);
|
|
462
|
+
if (eventLine && dataLine) {
|
|
463
|
+
const eventType = eventLine[1];
|
|
464
|
+
const eventData = JSON.parse(dataLine[1]);
|
|
465
|
+
if (eventType === "complete") {
|
|
466
|
+
reader.cancel();
|
|
467
|
+
return eventData;
|
|
468
|
+
} else if (eventType === "error") {
|
|
469
|
+
reader.cancel();
|
|
470
|
+
throw new Error(eventData.message);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
throw new Error("Upload completed but no final game data received");
|
|
420
476
|
},
|
|
421
477
|
update: (gameId, props) => client["request"](`/games/${gameId}`, "PATCH", props),
|
|
422
478
|
delete: (gameId) => client["request"](`/games/${gameId}`, "DELETE")
|
|
@@ -949,7 +1005,7 @@ function createCreditsNamespace(client) {
|
|
|
949
1005
|
};
|
|
950
1006
|
return {
|
|
951
1007
|
balance: async () => {
|
|
952
|
-
const inventory = await client
|
|
1008
|
+
const inventory = await client["request"]("/inventory", "GET");
|
|
953
1009
|
const primaryCurrencyInventoryItem = inventory.find((item) => item.item?.slug === CURRENCIES.PRIMARY);
|
|
954
1010
|
return primaryCurrencyInventoryItem?.quantity ?? 0;
|
|
955
1011
|
},
|
|
@@ -958,7 +1014,10 @@ function createCreditsNamespace(client) {
|
|
|
958
1014
|
throw new Error("Amount must be positive");
|
|
959
1015
|
}
|
|
960
1016
|
const creditsItemId = await getCreditsItemId();
|
|
961
|
-
const result = await client
|
|
1017
|
+
const result = await client["request"]("/inventory/add", "POST", {
|
|
1018
|
+
itemId: creditsItemId,
|
|
1019
|
+
qty: amount
|
|
1020
|
+
});
|
|
962
1021
|
client["emit"]("inventoryChange", {
|
|
963
1022
|
itemId: creditsItemId,
|
|
964
1023
|
delta: amount,
|
|
@@ -971,7 +1030,10 @@ function createCreditsNamespace(client) {
|
|
|
971
1030
|
throw new Error("Amount must be positive");
|
|
972
1031
|
}
|
|
973
1032
|
const creditsItemId = await getCreditsItemId();
|
|
974
|
-
const result = await client
|
|
1033
|
+
const result = await client["request"]("/inventory/remove", "POST", {
|
|
1034
|
+
itemId: creditsItemId,
|
|
1035
|
+
qty: amount
|
|
1036
|
+
});
|
|
975
1037
|
client["emit"]("inventoryChange", {
|
|
976
1038
|
itemId: creditsItemId,
|
|
977
1039
|
delta: -amount,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playcademy/sdk",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.28",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -21,14 +21,18 @@
|
|
|
21
21
|
],
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "bun build.js",
|
|
24
|
-
"bump": "bunx bumpp --no-tag --no-push -c \"chore(@playcademy/sdk): release v%s\"",
|
|
25
|
-
"pub": "bun run build && bun run bump && bun publish --access public"
|
|
24
|
+
"bump": "SKIP_TESTS=1 bunx bumpp --no-tag --no-push -c \"chore(@playcademy/sdk): release v%s\"",
|
|
25
|
+
"pub": "bun run build && bun run bump && bun publish --access public",
|
|
26
|
+
"test": "bun test",
|
|
27
|
+
"test:watch": "bun test --watch"
|
|
26
28
|
},
|
|
27
29
|
"dependencies": {
|
|
28
30
|
"@playcademy/logger": "0.0.1"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
33
|
"@playcademy/data": "0.0.1",
|
|
34
|
+
"@playcademy/sandbox": "0.1.0-beta.10",
|
|
35
|
+
"@playcademy/test": "0.0.1",
|
|
32
36
|
"@types/bun": "latest",
|
|
33
37
|
"typescript": "^5.7.2",
|
|
34
38
|
"yocto-spinner": "^0.2.2"
|