@playcademy/sdk 0.0.1-beta.3 → 0.0.1-beta.5
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/build.ts +50 -0
- package/package.json +3 -8
- package/src/bus.ts +74 -0
- package/src/core/client.ts +416 -0
- package/src/core/errors.ts +20 -0
- package/src/core/request.ts +104 -0
- package/src/runtime.ts +61 -0
- package/src/types.ts +55 -0
- package/sst-env.d.ts +9 -0
- package/tsconfig.json +27 -0
- package/tsconfig.types.json +13 -0
- package/dist/bus.d.ts +0 -37
- package/dist/core/client.d.ts +0 -144
- package/dist/core/errors.d.ts +0 -11
- package/dist/core/request.d.ts +0 -24
- package/dist/runtime.d.ts +0 -7
- package/dist/runtime.js +0 -7427
- package/dist/types.d.ts +0 -43
- package/dist/types.js +0 -0
package/src/runtime.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { bus, type BusEventMap, BusEvents } from './bus'
|
|
2
|
+
import { PlaycademyClient } from './core/client'
|
|
3
|
+
|
|
4
|
+
/** For Node, SSR, dashboards, etc. */
|
|
5
|
+
export { PlaycademyClient } from './core/client'
|
|
6
|
+
|
|
7
|
+
/** Factory for code running *inside* the CADEMY loader (games) */
|
|
8
|
+
export async function initFromWindow(): Promise<PlaycademyClient> {
|
|
9
|
+
// ------------------------------------------------------------------
|
|
10
|
+
// 0. Runtime guard
|
|
11
|
+
// ------------------------------------------------------------------
|
|
12
|
+
if (typeof window === 'undefined') {
|
|
13
|
+
throw new Error('initFromWindow must run in a browser context')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ------------------------------------------------------------------
|
|
17
|
+
// 1. Await bootstrap from loader (handles both module + iframe modes)
|
|
18
|
+
// ------------------------------------------------------------------
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
const preloaded = (window as any).PLAYCADEMY as
|
|
21
|
+
| Partial<BusEventMap[BusEvents.INIT]>
|
|
22
|
+
| undefined
|
|
23
|
+
|
|
24
|
+
const config: BusEventMap[BusEvents.INIT] = preloaded?.token
|
|
25
|
+
? (preloaded as BusEventMap[BusEvents.INIT])
|
|
26
|
+
: await new Promise<BusEventMap[BusEvents.INIT]>(resolve =>
|
|
27
|
+
bus.on(BusEvents.INIT, resolve),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
// ------------------------------------------------------------------
|
|
31
|
+
// 2. Spin up API client with the short‑lived Game‑JWT
|
|
32
|
+
// ------------------------------------------------------------------
|
|
33
|
+
const client = new PlaycademyClient({
|
|
34
|
+
baseUrl: config.baseUrl,
|
|
35
|
+
token: config.token,
|
|
36
|
+
gameId: config.gameId,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// ------------------------------------------------------------------
|
|
40
|
+
// 3. React to runtime events automatically
|
|
41
|
+
// ------------------------------------------------------------------
|
|
42
|
+
bus.on(BusEvents.TOKEN_REFRESH, ({ token }) => client.setToken(token))
|
|
43
|
+
|
|
44
|
+
// ------------------------------------------------------------------
|
|
45
|
+
// 4. Tell the parent loader we're alive
|
|
46
|
+
// ------------------------------------------------------------------
|
|
47
|
+
bus.emit(BusEvents.READY, undefined)
|
|
48
|
+
|
|
49
|
+
// ------------------------------------------------------------------
|
|
50
|
+
// (Expose for debugging if dev tools are open)
|
|
51
|
+
// ------------------------------------------------------------------
|
|
52
|
+
if (import.meta.env?.MODE === 'development') {
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
|
+
;(window as any).PLAYCADEMY_CLIENT = client
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return client
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { bus, BusEvents } from './bus'
|
|
61
|
+
export { PlaycademyError } from './core/errors'
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
User,
|
|
3
|
+
InventoryItemWithReward,
|
|
4
|
+
Game,
|
|
5
|
+
DeveloperKey,
|
|
6
|
+
DeveloperStatusResponse,
|
|
7
|
+
MapElement,
|
|
8
|
+
Reward,
|
|
9
|
+
InsertReward,
|
|
10
|
+
ManifestV1,
|
|
11
|
+
UpdateReward,
|
|
12
|
+
} from '@playcademy/types'
|
|
13
|
+
|
|
14
|
+
export interface ClientConfig {
|
|
15
|
+
baseUrl: string
|
|
16
|
+
token?: string
|
|
17
|
+
gameId?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ClientEvents {
|
|
21
|
+
authChange: { token: string | null }
|
|
22
|
+
inventoryChange: { rewardId: string; delta: number; newTotal: number }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type GameContextPayload = {
|
|
26
|
+
token: string
|
|
27
|
+
baseUrl: string
|
|
28
|
+
gameId: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type EventListeners = {
|
|
32
|
+
[E in keyof ClientEvents]?: Array<(payload: ClientEvents[E]) => void>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type GameWithManifest = Game & { manifest: ManifestV1 }
|
|
36
|
+
export type DeveloperStatusValue = DeveloperStatusResponse['status']
|
|
37
|
+
export type GameState = Record<string, unknown>
|
|
38
|
+
|
|
39
|
+
export type LoginResponse = { token: string }
|
|
40
|
+
export type GameTokenResponse = { token: string; exp: number }
|
|
41
|
+
export type StartSessionResponse = { sessionId: string }
|
|
42
|
+
export type InventoryMutationResponse = { newTotal: number }
|
|
43
|
+
|
|
44
|
+
export type {
|
|
45
|
+
User,
|
|
46
|
+
InventoryItemWithReward,
|
|
47
|
+
Game,
|
|
48
|
+
ManifestV1,
|
|
49
|
+
DeveloperKey,
|
|
50
|
+
DeveloperStatusResponse,
|
|
51
|
+
MapElement,
|
|
52
|
+
Reward,
|
|
53
|
+
InsertReward,
|
|
54
|
+
UpdateReward,
|
|
55
|
+
}
|
package/sst-env.d.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Enable latest features
|
|
4
|
+
"lib": ["ESNext", "DOM"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
|
|
11
|
+
// Bundler mode
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
// Best practices
|
|
18
|
+
"strict": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
|
|
22
|
+
// Some stricter flags (disabled by default)
|
|
23
|
+
"noUnusedLocals": false,
|
|
24
|
+
"noUnusedParameters": false,
|
|
25
|
+
"noPropertyAccessFromIndexSignature": false
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"noEmit": false,
|
|
5
|
+
"emitDeclarationOnly": true,
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"skipLibCheck": true
|
|
10
|
+
},
|
|
11
|
+
"include": ["src/**/*.ts"],
|
|
12
|
+
"exclude": ["node_modules", "**/*.test.ts"]
|
|
13
|
+
}
|
package/dist/bus.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { GameContextPayload } from './types';
|
|
2
|
-
export declare enum BusEvents {
|
|
3
|
-
INIT = "PLAYCADEMY_INIT",
|
|
4
|
-
TOKEN_REFRESH = "PLAYCADEMY_TOKEN_REFRESH",
|
|
5
|
-
PAUSE = "PLAYCADEMY_PAUSE",
|
|
6
|
-
RESUME = "PLAYCADEMY_RESUME",
|
|
7
|
-
FORCE_EXIT = "PLAYCADEMY_FORCE_EXIT",
|
|
8
|
-
OVERLAY = "PLAYCADEMY_OVERLAY",
|
|
9
|
-
READY = "PLAYCADEMY_READY",
|
|
10
|
-
EXIT = "PLAYCADEMY_EXIT",
|
|
11
|
-
TELEMETRY = "PLAYCADEMY_TELEMETRY"
|
|
12
|
-
}
|
|
13
|
-
type BusHandler<T = unknown> = (payload: T) => void;
|
|
14
|
-
export type BusEventMap = {
|
|
15
|
-
[BusEvents.INIT]: GameContextPayload;
|
|
16
|
-
[BusEvents.TOKEN_REFRESH]: {
|
|
17
|
-
token: string;
|
|
18
|
-
exp: number;
|
|
19
|
-
};
|
|
20
|
-
[BusEvents.PAUSE]: void;
|
|
21
|
-
[BusEvents.RESUME]: void;
|
|
22
|
-
[BusEvents.FORCE_EXIT]: void;
|
|
23
|
-
[BusEvents.OVERLAY]: boolean;
|
|
24
|
-
[BusEvents.READY]: void;
|
|
25
|
-
[BusEvents.EXIT]: void;
|
|
26
|
-
[BusEvents.TELEMETRY]: {
|
|
27
|
-
fps: number;
|
|
28
|
-
mem: number;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
interface Bus {
|
|
32
|
-
emit<K extends BusEvents>(type: K, payload: BusEventMap[K]): void;
|
|
33
|
-
on<K extends BusEvents>(type: K, handler: BusHandler<BusEventMap[K]>): void;
|
|
34
|
-
off<K extends BusEvents>(type: K, handler: BusHandler<BusEventMap[K]>): void;
|
|
35
|
-
}
|
|
36
|
-
export declare const bus: Bus;
|
|
37
|
-
export {};
|
package/dist/core/client.d.ts
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { type Method } from './request';
|
|
2
|
-
import { type Game, type GameWithManifest, type UpsertGameMetadataInput, type InsertReward, type UpdateReward } from '@playcademy/data/schemas';
|
|
3
|
-
import type { GameState, InventoryItemWithReward, ClientConfig, ClientEvents, LoginResponse, GameTokenResponse, StartSessionResponse, InventoryMutationResponse, DeveloperStatusValue } from '../types';
|
|
4
|
-
export declare class PlaycademyClient {
|
|
5
|
-
private baseUrl;
|
|
6
|
-
private token?;
|
|
7
|
-
private gameId?;
|
|
8
|
-
private listeners;
|
|
9
|
-
private internalClientSessionId?;
|
|
10
|
-
constructor(config: ClientConfig);
|
|
11
|
-
private _initializeInternalSession;
|
|
12
|
-
getBaseUrl(): string;
|
|
13
|
-
on<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): void;
|
|
14
|
-
private emit;
|
|
15
|
-
setToken(token: string | null): void;
|
|
16
|
-
onAuthChange(callback: (token: string | null) => void): void;
|
|
17
|
-
protected request<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
18
|
-
private _ensureGameId;
|
|
19
|
-
auth: {
|
|
20
|
-
logout: () => Promise<void>;
|
|
21
|
-
};
|
|
22
|
-
runtime: {
|
|
23
|
-
getGameToken: (gameId: string, options?: {
|
|
24
|
-
apply?: boolean;
|
|
25
|
-
}) => Promise<GameTokenResponse>;
|
|
26
|
-
exit: () => Promise<void>;
|
|
27
|
-
};
|
|
28
|
-
games: {
|
|
29
|
-
fetch: (gameIdOrSlug: string) => Promise<GameWithManifest>;
|
|
30
|
-
list: () => Promise<Array<Game>>;
|
|
31
|
-
saveState: (state: Record<string, unknown>) => Promise<void>;
|
|
32
|
-
loadState: () => Promise<GameState>;
|
|
33
|
-
startSession: (gameId?: string) => Promise<StartSessionResponse>;
|
|
34
|
-
endSession: (sessionId: string, gameId?: string) => Promise<void>;
|
|
35
|
-
};
|
|
36
|
-
users: {
|
|
37
|
-
me: () => Promise<{
|
|
38
|
-
id: string;
|
|
39
|
-
name: string;
|
|
40
|
-
username: string | null;
|
|
41
|
-
email: string;
|
|
42
|
-
emailVerified: boolean;
|
|
43
|
-
image: string | null;
|
|
44
|
-
role: "admin" | "player" | "developer";
|
|
45
|
-
developerStatus: "none" | "pending" | "approved";
|
|
46
|
-
createdAt: Date;
|
|
47
|
-
updatedAt: Date;
|
|
48
|
-
}>;
|
|
49
|
-
inventory: {
|
|
50
|
-
get: () => Promise<InventoryItemWithReward[]>;
|
|
51
|
-
add: (rewardId: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
52
|
-
spend: (rewardId: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
dev: {
|
|
56
|
-
auth: {
|
|
57
|
-
applyForDeveloper: () => Promise<void>;
|
|
58
|
-
getDeveloperStatus: () => Promise<DeveloperStatusValue>;
|
|
59
|
-
};
|
|
60
|
-
games: {
|
|
61
|
-
upsert: (slug: string, metadata: UpsertGameMetadataInput, file: File | Blob) => Promise<Game>;
|
|
62
|
-
update: (gameId: string, props: Partial<Game>) => Promise<void>;
|
|
63
|
-
delete: (gameId: string) => Promise<void>;
|
|
64
|
-
};
|
|
65
|
-
keys: {
|
|
66
|
-
createKey: (gameId: string, label?: string) => Promise<{
|
|
67
|
-
id: string;
|
|
68
|
-
createdAt: Date;
|
|
69
|
-
userId: string;
|
|
70
|
-
label: string | null;
|
|
71
|
-
keyHash: string;
|
|
72
|
-
}>;
|
|
73
|
-
listKeys: (gameId: string) => Promise<{
|
|
74
|
-
id: string;
|
|
75
|
-
createdAt: Date;
|
|
76
|
-
userId: string;
|
|
77
|
-
label: string | null;
|
|
78
|
-
keyHash: string;
|
|
79
|
-
}[]>;
|
|
80
|
-
revokeKey: (keyId: string) => Promise<void>;
|
|
81
|
-
};
|
|
82
|
-
};
|
|
83
|
-
maps: {
|
|
84
|
-
elements: (mapId: string) => Promise<{
|
|
85
|
-
id: string;
|
|
86
|
-
mapId: string | null;
|
|
87
|
-
elementSlug: string;
|
|
88
|
-
interactionType: "game_entry" | "game_registry" | "info" | "teleport" | "door_in" | "door_out" | "npc_interaction" | "quest_trigger";
|
|
89
|
-
metadata: ({
|
|
90
|
-
description?: string | undefined;
|
|
91
|
-
sourceTiledObjects?: Record<string, unknown>[] | undefined;
|
|
92
|
-
} & {
|
|
93
|
-
[k: string]: unknown;
|
|
94
|
-
}) | null;
|
|
95
|
-
gameId: string | null;
|
|
96
|
-
}[]>;
|
|
97
|
-
};
|
|
98
|
-
admin: {
|
|
99
|
-
games: {
|
|
100
|
-
pauseGame: (gameId: string) => Promise<void>;
|
|
101
|
-
resumeGame: (gameId: string) => Promise<void>;
|
|
102
|
-
};
|
|
103
|
-
rewards: {
|
|
104
|
-
createReward: (props: InsertReward) => Promise<{
|
|
105
|
-
id: string;
|
|
106
|
-
type: "currency" | "badge" | "trophy" | "unlock" | "upgrade" | "other";
|
|
107
|
-
displayName: string;
|
|
108
|
-
description: string | null;
|
|
109
|
-
metadata: unknown;
|
|
110
|
-
internalName: string;
|
|
111
|
-
}>;
|
|
112
|
-
getReward: (rewardId: string) => Promise<{
|
|
113
|
-
id: string;
|
|
114
|
-
type: "currency" | "badge" | "trophy" | "unlock" | "upgrade" | "other";
|
|
115
|
-
displayName: string;
|
|
116
|
-
description: string | null;
|
|
117
|
-
metadata: unknown;
|
|
118
|
-
internalName: string;
|
|
119
|
-
}>;
|
|
120
|
-
listRewards: () => Promise<{
|
|
121
|
-
id: string;
|
|
122
|
-
type: "currency" | "badge" | "trophy" | "unlock" | "upgrade" | "other";
|
|
123
|
-
displayName: string;
|
|
124
|
-
description: string | null;
|
|
125
|
-
metadata: unknown;
|
|
126
|
-
internalName: string;
|
|
127
|
-
}[]>;
|
|
128
|
-
updateReward: (rewardId: string, props: UpdateReward) => Promise<{
|
|
129
|
-
id: string;
|
|
130
|
-
type: "currency" | "badge" | "trophy" | "unlock" | "upgrade" | "other";
|
|
131
|
-
displayName: string;
|
|
132
|
-
description: string | null;
|
|
133
|
-
metadata: unknown;
|
|
134
|
-
internalName: string;
|
|
135
|
-
}>;
|
|
136
|
-
deleteReward: (rewardId: string) => Promise<void>;
|
|
137
|
-
};
|
|
138
|
-
};
|
|
139
|
-
telemetry: {
|
|
140
|
-
pushMetrics: (metrics: Record<string, number>) => Promise<void>;
|
|
141
|
-
};
|
|
142
|
-
ping(): string;
|
|
143
|
-
static login(baseUrl: string, email: string, password: string): Promise<LoginResponse>;
|
|
144
|
-
}
|
package/dist/core/errors.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base error class for Cademy SDK specific errors.
|
|
3
|
-
*/
|
|
4
|
-
export declare class PlaycademyError extends Error {
|
|
5
|
-
constructor(message: string);
|
|
6
|
-
}
|
|
7
|
-
export declare class ApiError extends Error {
|
|
8
|
-
status: number;
|
|
9
|
-
details: unknown;
|
|
10
|
-
constructor(status: number, message: string, details: unknown);
|
|
11
|
-
}
|
package/dist/core/request.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type ManifestV1 } from '@playcademy/data/schemas';
|
|
2
|
-
/** Permitted HTTP verbs */
|
|
3
|
-
export type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
4
|
-
export interface RequestOptions {
|
|
5
|
-
path: string;
|
|
6
|
-
baseUrl: string;
|
|
7
|
-
token?: string | null;
|
|
8
|
-
method?: Method;
|
|
9
|
-
body?: unknown;
|
|
10
|
-
extraHeaders?: Record<string, string>;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Thin wrapper around `fetch` that:
|
|
14
|
-
* • attaches Bearer token if provided
|
|
15
|
-
* • stringifies JSON bodies and sets Content‑Type
|
|
16
|
-
* • passes FormData untouched so the browser adds multipart boundary
|
|
17
|
-
* • normalises non‑2xx responses into ApiError
|
|
18
|
-
* • auto‑parses JSON responses, falls back to text/void
|
|
19
|
-
*/
|
|
20
|
-
export declare function request<T = unknown>({ path, baseUrl, token, method, body, extraHeaders, }: RequestOptions): Promise<T>;
|
|
21
|
-
/**
|
|
22
|
-
* Fetches, parses, and validates the playcademy.manifest.json file from a given base URL.
|
|
23
|
-
*/
|
|
24
|
-
export declare function fetchManifest(assetBundleBase: string): Promise<ManifestV1>;
|
package/dist/runtime.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { PlaycademyClient } from './core/client';
|
|
2
|
-
/** For Node, SSR, dashboards, etc. */
|
|
3
|
-
export { PlaycademyClient } from './core/client';
|
|
4
|
-
/** Factory for code running *inside* the CADEMY loader (games) */
|
|
5
|
-
export declare function initFromWindow(): Promise<PlaycademyClient>;
|
|
6
|
-
export { bus, BusEvents } from './bus';
|
|
7
|
-
export { PlaycademyError } from './core/errors';
|