@playcademy/sdk 0.0.1-beta.24 → 0.0.1-beta.26
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 +4 -6
- package/dist/core/client.d.ts +67 -47
- package/dist/core/namespaces/admin.d.ts +24 -20
- package/dist/core/namespaces/auth.d.ts +1 -1
- package/dist/core/namespaces/credits.d.ts +1 -1
- package/dist/core/namespaces/dev.d.ts +185 -15
- package/dist/core/namespaces/games.d.ts +8 -4
- package/dist/core/namespaces/levels.d.ts +2 -2
- package/dist/core/namespaces/maps.d.ts +4 -9
- package/dist/core/namespaces/runtime.d.ts +1 -2
- package/dist/core/namespaces/shop.d.ts +1 -2
- package/dist/core/namespaces/telemetry.d.ts +1 -1
- package/dist/core/namespaces/users.d.ts +18 -18
- package/dist/core/request.d.ts +1 -1
- package/dist/core/static/init.d.ts +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +575 -97
- package/dist/types.d.ts +3 -36
- package/dist/types.js +363 -8
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -10,6 +10,86 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
12
12
|
|
|
13
|
+
// ../logger/src/index.ts
|
|
14
|
+
var isBrowser = () => {
|
|
15
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
16
|
+
}, colors, getLevelColor = (level) => {
|
|
17
|
+
switch (level) {
|
|
18
|
+
case "debug":
|
|
19
|
+
return colors.blue;
|
|
20
|
+
case "info":
|
|
21
|
+
return colors.cyan;
|
|
22
|
+
case "warn":
|
|
23
|
+
return colors.yellow;
|
|
24
|
+
case "error":
|
|
25
|
+
return colors.red;
|
|
26
|
+
default:
|
|
27
|
+
return colors.reset;
|
|
28
|
+
}
|
|
29
|
+
}, logInBrowser = (level, message, context) => {
|
|
30
|
+
const timestamp = new Date().toISOString();
|
|
31
|
+
const levelUpper = level.toUpperCase();
|
|
32
|
+
const consoleMethod = getConsoleMethod(level);
|
|
33
|
+
if (context && Object.keys(context).length > 0) {
|
|
34
|
+
consoleMethod(`[${timestamp}] ${levelUpper}`, message, context);
|
|
35
|
+
} else {
|
|
36
|
+
consoleMethod(`[${timestamp}] ${levelUpper}`, message);
|
|
37
|
+
}
|
|
38
|
+
}, logOnServer = (level, message, context) => {
|
|
39
|
+
const consoleMethod = getConsoleMethod(level);
|
|
40
|
+
if (true) {
|
|
41
|
+
const timestamp = new Date().toISOString();
|
|
42
|
+
const levelColor = getLevelColor(level);
|
|
43
|
+
const levelUpper = level.toUpperCase().padEnd(5);
|
|
44
|
+
const coloredPrefix = `${colors.dim}[${timestamp}]${colors.reset} ${levelColor}${levelUpper}${colors.reset}`;
|
|
45
|
+
if (context && Object.keys(context).length > 0) {
|
|
46
|
+
consoleMethod(`${coloredPrefix} ${message}`, context);
|
|
47
|
+
} else {
|
|
48
|
+
consoleMethod(`${coloredPrefix} ${message}`);
|
|
49
|
+
}
|
|
50
|
+
} else {}
|
|
51
|
+
}, getConsoleMethod = (level) => {
|
|
52
|
+
switch (level) {
|
|
53
|
+
case "debug":
|
|
54
|
+
return console.debug;
|
|
55
|
+
case "info":
|
|
56
|
+
return console.info;
|
|
57
|
+
case "warn":
|
|
58
|
+
return console.warn;
|
|
59
|
+
case "error":
|
|
60
|
+
return console.error;
|
|
61
|
+
default:
|
|
62
|
+
return console.log;
|
|
63
|
+
}
|
|
64
|
+
}, performLog = (level, message, context) => {
|
|
65
|
+
if (level === "debug" && false) {}
|
|
66
|
+
if (isBrowser()) {
|
|
67
|
+
logInBrowser(level, message, context);
|
|
68
|
+
} else {
|
|
69
|
+
logOnServer(level, message, context);
|
|
70
|
+
}
|
|
71
|
+
}, createLogger = () => {
|
|
72
|
+
return {
|
|
73
|
+
debug: (message, context) => performLog("debug", message, context),
|
|
74
|
+
info: (message, context) => performLog("info", message, context),
|
|
75
|
+
warn: (message, context) => performLog("warn", message, context),
|
|
76
|
+
error: (message, context) => performLog("error", message, context),
|
|
77
|
+
log: performLog
|
|
78
|
+
};
|
|
79
|
+
}, log;
|
|
80
|
+
var init_src = __esm(() => {
|
|
81
|
+
colors = {
|
|
82
|
+
reset: "\x1B[0m",
|
|
83
|
+
dim: "\x1B[2m",
|
|
84
|
+
red: "\x1B[31m",
|
|
85
|
+
yellow: "\x1B[33m",
|
|
86
|
+
blue: "\x1B[34m",
|
|
87
|
+
cyan: "\x1B[36m",
|
|
88
|
+
gray: "\x1B[90m"
|
|
89
|
+
};
|
|
90
|
+
log = createLogger();
|
|
91
|
+
});
|
|
92
|
+
|
|
13
93
|
// src/core/errors.ts
|
|
14
94
|
var PlaycademyError, ApiError;
|
|
15
95
|
var init_errors = __esm(() => {
|
|
@@ -31,68 +111,6 @@ var init_errors = __esm(() => {
|
|
|
31
111
|
};
|
|
32
112
|
});
|
|
33
113
|
|
|
34
|
-
// src/core/request.ts
|
|
35
|
-
async function request({
|
|
36
|
-
path,
|
|
37
|
-
baseUrl,
|
|
38
|
-
token,
|
|
39
|
-
method = "GET",
|
|
40
|
-
body,
|
|
41
|
-
extraHeaders = {}
|
|
42
|
-
}) {
|
|
43
|
-
const url = baseUrl.replace(/\/$/, "") + (path.startsWith("/") ? path : `/${path}`);
|
|
44
|
-
const headers = { ...extraHeaders };
|
|
45
|
-
let payload;
|
|
46
|
-
if (body instanceof FormData) {
|
|
47
|
-
payload = body;
|
|
48
|
-
} else if (body !== undefined && body !== null) {
|
|
49
|
-
payload = JSON.stringify(body);
|
|
50
|
-
headers["Content-Type"] = "application/json";
|
|
51
|
-
}
|
|
52
|
-
if (token)
|
|
53
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
54
|
-
const res = await fetch(url, {
|
|
55
|
-
method,
|
|
56
|
-
headers,
|
|
57
|
-
body: payload,
|
|
58
|
-
credentials: "omit"
|
|
59
|
-
});
|
|
60
|
-
if (!res.ok) {
|
|
61
|
-
const errorBody = await res.clone().json().catch(() => res.text().catch(() => {
|
|
62
|
-
return;
|
|
63
|
-
})) ?? undefined;
|
|
64
|
-
throw new ApiError(res.status, res.statusText, errorBody);
|
|
65
|
-
}
|
|
66
|
-
if (res.status === 204)
|
|
67
|
-
return;
|
|
68
|
-
const contentType = res.headers.get("content-type") ?? "";
|
|
69
|
-
if (contentType.includes("application/json")) {
|
|
70
|
-
return await res.json();
|
|
71
|
-
}
|
|
72
|
-
return await res.text();
|
|
73
|
-
}
|
|
74
|
-
async function fetchManifest(assetBundleBase) {
|
|
75
|
-
const manifestUrl = `${assetBundleBase.replace(/\/$/, "")}/playcademy.manifest.json`;
|
|
76
|
-
try {
|
|
77
|
-
const response = await fetch(manifestUrl);
|
|
78
|
-
if (!response.ok) {
|
|
79
|
-
console.error(`[fetchManifest] Failed to fetch manifest from ${manifestUrl}. Status: ${response.status}`);
|
|
80
|
-
throw new PlaycademyError(`Failed to fetch manifest: ${response.status} ${response.statusText}`);
|
|
81
|
-
}
|
|
82
|
-
return await response.json();
|
|
83
|
-
} catch (error) {
|
|
84
|
-
if (error instanceof PlaycademyError) {
|
|
85
|
-
throw error;
|
|
86
|
-
}
|
|
87
|
-
console.error(`[fetchManifest] Error fetching or parsing manifest from ${manifestUrl}:`, error);
|
|
88
|
-
throw new PlaycademyError("Failed to load or parse game manifest");
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
var init_request = __esm(() => {
|
|
92
|
-
init_errors();
|
|
93
|
-
init_errors();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
114
|
// src/core/namespaces/auth.ts
|
|
97
115
|
function createAuthNamespace(client) {
|
|
98
116
|
return {
|
|
@@ -208,7 +226,10 @@ function createRuntimeNamespace(client) {
|
|
|
208
226
|
try {
|
|
209
227
|
await client.games.endSession(client["internalClientSessionId"], client["gameId"]);
|
|
210
228
|
} catch (error) {
|
|
211
|
-
|
|
229
|
+
log.error("[Playcademy SDK] Failed to auto-end session:", {
|
|
230
|
+
sessionId: client["internalClientSessionId"],
|
|
231
|
+
error
|
|
232
|
+
});
|
|
212
233
|
}
|
|
213
234
|
}
|
|
214
235
|
messaging.send("PLAYCADEMY_EXIT" /* EXIT */, undefined);
|
|
@@ -216,9 +237,74 @@ function createRuntimeNamespace(client) {
|
|
|
216
237
|
};
|
|
217
238
|
}
|
|
218
239
|
var init_runtime = __esm(() => {
|
|
240
|
+
init_src();
|
|
219
241
|
init_messaging();
|
|
220
242
|
});
|
|
221
243
|
|
|
244
|
+
// src/core/request.ts
|
|
245
|
+
async function request({
|
|
246
|
+
path,
|
|
247
|
+
baseUrl,
|
|
248
|
+
token,
|
|
249
|
+
method = "GET",
|
|
250
|
+
body,
|
|
251
|
+
extraHeaders = {}
|
|
252
|
+
}) {
|
|
253
|
+
const url = baseUrl.replace(/\/$/, "") + (path.startsWith("/") ? path : `/${path}`);
|
|
254
|
+
const headers = { ...extraHeaders };
|
|
255
|
+
let payload;
|
|
256
|
+
if (body instanceof FormData) {
|
|
257
|
+
payload = body;
|
|
258
|
+
} else if (body !== undefined && body !== null) {
|
|
259
|
+
payload = JSON.stringify(body);
|
|
260
|
+
headers["Content-Type"] = "application/json";
|
|
261
|
+
}
|
|
262
|
+
if (token)
|
|
263
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
264
|
+
const res = await fetch(url, {
|
|
265
|
+
method,
|
|
266
|
+
headers,
|
|
267
|
+
body: payload,
|
|
268
|
+
credentials: "omit"
|
|
269
|
+
});
|
|
270
|
+
if (!res.ok) {
|
|
271
|
+
const errorBody = await res.clone().json().catch(() => res.text().catch(() => {
|
|
272
|
+
return;
|
|
273
|
+
})) ?? undefined;
|
|
274
|
+
throw new ApiError(res.status, res.statusText, errorBody);
|
|
275
|
+
}
|
|
276
|
+
if (res.status === 204)
|
|
277
|
+
return;
|
|
278
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
279
|
+
if (contentType.includes("application/json")) {
|
|
280
|
+
return await res.json();
|
|
281
|
+
}
|
|
282
|
+
return await res.text();
|
|
283
|
+
}
|
|
284
|
+
async function fetchManifest(assetBundleBase) {
|
|
285
|
+
const manifestUrl = `${assetBundleBase.replace(/\/$/, "")}/playcademy.manifest.json`;
|
|
286
|
+
try {
|
|
287
|
+
const response = await fetch(manifestUrl);
|
|
288
|
+
if (!response.ok) {
|
|
289
|
+
log.error(`[fetchManifest] Failed to fetch manifest from ${manifestUrl}. Status: ${response.status}`);
|
|
290
|
+
throw new PlaycademyError(`Failed to fetch manifest: ${response.status} ${response.statusText}`);
|
|
291
|
+
}
|
|
292
|
+
return await response.json();
|
|
293
|
+
} catch (error) {
|
|
294
|
+
if (error instanceof PlaycademyError) {
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
log.error(`[Playcademy SDK] Error fetching or parsing manifest from ${manifestUrl}:`, {
|
|
298
|
+
error
|
|
299
|
+
});
|
|
300
|
+
throw new PlaycademyError("Failed to load or parse game manifest");
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
var init_request = __esm(() => {
|
|
304
|
+
init_src();
|
|
305
|
+
init_errors();
|
|
306
|
+
});
|
|
307
|
+
|
|
222
308
|
// src/core/namespaces/games.ts
|
|
223
309
|
function createGamesNamespace(client) {
|
|
224
310
|
return {
|
|
@@ -263,15 +349,17 @@ function createUsersNamespace(client) {
|
|
|
263
349
|
const resolveItemId = async (identifier) => {
|
|
264
350
|
if (UUID_REGEX.test(identifier))
|
|
265
351
|
return identifier;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
352
|
+
const gameId = client["gameId"];
|
|
353
|
+
const cacheKey = gameId ? `${identifier}:${gameId}` : identifier;
|
|
354
|
+
if (itemIdCache.has(cacheKey)) {
|
|
355
|
+
return itemIdCache.get(cacheKey);
|
|
356
|
+
}
|
|
357
|
+
const queryParams = new URLSearchParams({ slug: identifier });
|
|
358
|
+
if (gameId)
|
|
359
|
+
queryParams.append("gameId", gameId);
|
|
360
|
+
const item = await client["request"](`/items/resolve?${queryParams.toString()}`, "GET");
|
|
361
|
+
itemIdCache.set(cacheKey, item.id);
|
|
362
|
+
return item.id;
|
|
275
363
|
};
|
|
276
364
|
return {
|
|
277
365
|
me: async () => {
|
|
@@ -300,12 +388,9 @@ function createUsersNamespace(client) {
|
|
|
300
388
|
return res;
|
|
301
389
|
},
|
|
302
390
|
quantity: async (identifier) => {
|
|
391
|
+
const itemId = await resolveItemId(identifier);
|
|
303
392
|
const inventory = await client.users.inventory.get();
|
|
304
|
-
|
|
305
|
-
const item2 = inventory.find((inv) => inv.item?.id === identifier);
|
|
306
|
-
return item2?.quantity ?? 0;
|
|
307
|
-
}
|
|
308
|
-
const item = inventory.find((inv) => inv.item?.internalName === identifier);
|
|
393
|
+
const item = inventory.find((inv) => inv.item?.id === itemId);
|
|
309
394
|
return item?.quantity ?? 0;
|
|
310
395
|
},
|
|
311
396
|
has: async (identifier, minQuantity = 1) => {
|
|
@@ -337,9 +422,39 @@ function createDevNamespace(client) {
|
|
|
337
422
|
delete: (gameId) => client["request"](`/games/${gameId}`, "DELETE")
|
|
338
423
|
},
|
|
339
424
|
keys: {
|
|
340
|
-
createKey: (
|
|
341
|
-
listKeys: (
|
|
425
|
+
createKey: (label) => client["request"](`/dev/keys`, "POST", { label }),
|
|
426
|
+
listKeys: () => client["request"](`/dev/keys`, "GET"),
|
|
342
427
|
revokeKey: (keyId) => client["request"](`/dev/keys/${keyId}`, "DELETE")
|
|
428
|
+
},
|
|
429
|
+
items: {
|
|
430
|
+
create: (gameId, slug, itemData) => client["request"](`/games/${gameId}/items`, "POST", {
|
|
431
|
+
slug,
|
|
432
|
+
...itemData
|
|
433
|
+
}),
|
|
434
|
+
update: (gameId, itemId, updates) => client["request"](`/games/${gameId}/items/${itemId}`, "PATCH", updates),
|
|
435
|
+
list: (gameId) => client["request"](`/games/${gameId}/items`, "GET"),
|
|
436
|
+
get: (gameId, slug) => {
|
|
437
|
+
const queryParams = new URLSearchParams({ slug, gameId });
|
|
438
|
+
return client["request"](`/items/resolve?${queryParams.toString()}`, "GET");
|
|
439
|
+
},
|
|
440
|
+
delete: (gameId, itemId) => client["request"](`/games/${gameId}/items/${itemId}`, "DELETE"),
|
|
441
|
+
shop: {
|
|
442
|
+
create: (gameId, itemId, listingData) => {
|
|
443
|
+
return client["request"](`/games/${gameId}/items/${itemId}/shop-listing`, "POST", listingData);
|
|
444
|
+
},
|
|
445
|
+
get: (gameId, itemId) => {
|
|
446
|
+
return client["request"](`/games/${gameId}/items/${itemId}/shop-listing`, "GET");
|
|
447
|
+
},
|
|
448
|
+
update: (gameId, itemId, updates) => {
|
|
449
|
+
return client["request"](`/games/${gameId}/items/${itemId}/shop-listing`, "PATCH", updates);
|
|
450
|
+
},
|
|
451
|
+
delete: (gameId, itemId) => {
|
|
452
|
+
return client["request"](`/games/${gameId}/items/${itemId}/shop-listing`, "DELETE");
|
|
453
|
+
},
|
|
454
|
+
list: (gameId) => {
|
|
455
|
+
return client["request"](`/games/${gameId}/shop-listings`, "GET");
|
|
456
|
+
}
|
|
457
|
+
}
|
|
343
458
|
}
|
|
344
459
|
};
|
|
345
460
|
}
|
|
@@ -437,10 +552,365 @@ function createLevelsNamespace(client) {
|
|
|
437
552
|
};
|
|
438
553
|
}
|
|
439
554
|
|
|
555
|
+
// ../data/src/domains/user/table.ts
|
|
556
|
+
import { boolean, pgEnum, pgTable, text, timestamp, uniqueIndex } from "drizzle-orm/pg-core";
|
|
557
|
+
var userRoleEnum, developerStatusEnum, users, accounts, sessions, verification;
|
|
558
|
+
var init_table = __esm(() => {
|
|
559
|
+
userRoleEnum = pgEnum("user_role", ["admin", "player", "developer"]);
|
|
560
|
+
developerStatusEnum = pgEnum("developer_status", ["none", "pending", "approved"]);
|
|
561
|
+
users = pgTable("user", {
|
|
562
|
+
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
563
|
+
name: text("name").notNull(),
|
|
564
|
+
username: text("username").unique(),
|
|
565
|
+
email: text("email").notNull().unique(),
|
|
566
|
+
emailVerified: boolean("email_verified").notNull().default(false),
|
|
567
|
+
image: text("image"),
|
|
568
|
+
role: userRoleEnum("role").notNull().default("player"),
|
|
569
|
+
developerStatus: developerStatusEnum("developer_status").notNull().default("none"),
|
|
570
|
+
createdAt: timestamp("created_at", {
|
|
571
|
+
mode: "date",
|
|
572
|
+
withTimezone: true
|
|
573
|
+
}).notNull(),
|
|
574
|
+
updatedAt: timestamp("updated_at", {
|
|
575
|
+
mode: "date",
|
|
576
|
+
withTimezone: true
|
|
577
|
+
}).notNull()
|
|
578
|
+
});
|
|
579
|
+
accounts = pgTable("account", {
|
|
580
|
+
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
581
|
+
userId: text("userId").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
582
|
+
accountId: text("account_id").notNull(),
|
|
583
|
+
providerId: text("provider_id").notNull(),
|
|
584
|
+
accessToken: text("access_token"),
|
|
585
|
+
refreshToken: text("refresh_token"),
|
|
586
|
+
idToken: text("id_token"),
|
|
587
|
+
accessTokenExpiresAt: timestamp("access_token_expires_at", {
|
|
588
|
+
mode: "date",
|
|
589
|
+
withTimezone: true
|
|
590
|
+
}),
|
|
591
|
+
refreshTokenExpiresAt: timestamp("refresh_token_expires_at", {
|
|
592
|
+
mode: "date",
|
|
593
|
+
withTimezone: true
|
|
594
|
+
}),
|
|
595
|
+
scope: text("scope"),
|
|
596
|
+
password: text("password"),
|
|
597
|
+
createdAt: timestamp("created_at", {
|
|
598
|
+
mode: "date",
|
|
599
|
+
withTimezone: true
|
|
600
|
+
}).notNull(),
|
|
601
|
+
updatedAt: timestamp("updated_at", {
|
|
602
|
+
mode: "date",
|
|
603
|
+
withTimezone: true
|
|
604
|
+
}).notNull()
|
|
605
|
+
}, (table) => [uniqueIndex("account_provider_providerId_idx").on(table.accountId, table.providerId)]);
|
|
606
|
+
sessions = pgTable("session", {
|
|
607
|
+
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
608
|
+
userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
609
|
+
expiresAt: timestamp("expires_at", {
|
|
610
|
+
mode: "date",
|
|
611
|
+
withTimezone: true
|
|
612
|
+
}).notNull(),
|
|
613
|
+
token: text("token").notNull().unique(),
|
|
614
|
+
ipAddress: text("ip_address"),
|
|
615
|
+
userAgent: text("user_agent"),
|
|
616
|
+
createdAt: timestamp("created_at", {
|
|
617
|
+
mode: "date",
|
|
618
|
+
withTimezone: true
|
|
619
|
+
}).notNull(),
|
|
620
|
+
updatedAt: timestamp("updated_at", {
|
|
621
|
+
mode: "date",
|
|
622
|
+
withTimezone: true
|
|
623
|
+
}).notNull()
|
|
624
|
+
});
|
|
625
|
+
verification = pgTable("verification", {
|
|
626
|
+
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
627
|
+
identifier: text("identifier").notNull(),
|
|
628
|
+
value: text("value").notNull(),
|
|
629
|
+
expiresAt: timestamp("expires_at", {
|
|
630
|
+
mode: "date",
|
|
631
|
+
withTimezone: true
|
|
632
|
+
}).notNull(),
|
|
633
|
+
createdAt: timestamp("created_at", {
|
|
634
|
+
mode: "date",
|
|
635
|
+
withTimezone: true
|
|
636
|
+
}).notNull(),
|
|
637
|
+
updatedAt: timestamp("updated_at", {
|
|
638
|
+
mode: "date",
|
|
639
|
+
withTimezone: true
|
|
640
|
+
}).notNull()
|
|
641
|
+
});
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
// ../data/src/domains/developer/table.ts
|
|
645
|
+
import { pgTable as pgTable2, text as text2, timestamp as timestamp2, uuid, varchar } from "drizzle-orm/pg-core";
|
|
646
|
+
var developerKeys;
|
|
647
|
+
var init_table2 = __esm(() => {
|
|
648
|
+
init_table();
|
|
649
|
+
developerKeys = pgTable2("developer_keys", {
|
|
650
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
651
|
+
userId: text2("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
652
|
+
label: varchar("label", { length: 255 }),
|
|
653
|
+
keyHash: text2("key_hash").notNull().unique(),
|
|
654
|
+
createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow()
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
// ../data/src/domains/map/table.ts
|
|
659
|
+
import { relations } from "drizzle-orm";
|
|
660
|
+
import {
|
|
661
|
+
doublePrecision,
|
|
662
|
+
jsonb,
|
|
663
|
+
pgEnum as pgEnum2,
|
|
664
|
+
pgTable as pgTable3,
|
|
665
|
+
text as text3,
|
|
666
|
+
uniqueIndex as uniqueIndex2,
|
|
667
|
+
uuid as uuid2,
|
|
668
|
+
varchar as varchar2
|
|
669
|
+
} from "drizzle-orm/pg-core";
|
|
670
|
+
var interactionTypeEnum, maps, mapElements, mapElementsRelations, mapsRelations;
|
|
671
|
+
var init_table3 = __esm(() => {
|
|
672
|
+
init_table4();
|
|
673
|
+
interactionTypeEnum = pgEnum2("interaction_type", [
|
|
674
|
+
"game_entry",
|
|
675
|
+
"game_registry",
|
|
676
|
+
"info",
|
|
677
|
+
"teleport",
|
|
678
|
+
"door_in",
|
|
679
|
+
"door_out",
|
|
680
|
+
"npc_interaction",
|
|
681
|
+
"quest_trigger"
|
|
682
|
+
]);
|
|
683
|
+
maps = pgTable3("maps", {
|
|
684
|
+
id: uuid2("id").primaryKey().defaultRandom(),
|
|
685
|
+
identifier: varchar2("identifier", { length: 255 }).notNull().unique(),
|
|
686
|
+
displayName: varchar2("display_name", { length: 255 }).notNull(),
|
|
687
|
+
filePath: varchar2("file_path", { length: 255 }).notNull(),
|
|
688
|
+
tilesetBasePath: varchar2("tileset_base_path", { length: 255 }).notNull().default("/tilesets"),
|
|
689
|
+
defaultSpawnTileX: doublePrecision("default_spawn_tile_x").notNull().default(0),
|
|
690
|
+
defaultSpawnTileY: doublePrecision("default_spawn_tile_y").notNull().default(0),
|
|
691
|
+
description: text3("description")
|
|
692
|
+
});
|
|
693
|
+
mapElements = pgTable3("map_elements", {
|
|
694
|
+
id: uuid2("id").primaryKey().defaultRandom(),
|
|
695
|
+
mapId: uuid2("map_id").references(() => maps.id, {
|
|
696
|
+
onDelete: "cascade"
|
|
697
|
+
}),
|
|
698
|
+
elementSlug: varchar2("element_slug", { length: 255 }).notNull(),
|
|
699
|
+
interactionType: interactionTypeEnum("interaction_type").notNull(),
|
|
700
|
+
gameId: uuid2("game_id").references(() => games.id, {
|
|
701
|
+
onDelete: "set null"
|
|
702
|
+
}),
|
|
703
|
+
metadata: jsonb("metadata").$type().default({})
|
|
704
|
+
}, (table) => [uniqueIndex2("map_id_element_slug_unique_idx").on(table.mapId, table.elementSlug)]);
|
|
705
|
+
mapElementsRelations = relations(mapElements, ({ one }) => ({
|
|
706
|
+
game: one(games, {
|
|
707
|
+
fields: [mapElements.gameId],
|
|
708
|
+
references: [games.id]
|
|
709
|
+
}),
|
|
710
|
+
map: one(maps, {
|
|
711
|
+
fields: [mapElements.mapId],
|
|
712
|
+
references: [maps.id]
|
|
713
|
+
})
|
|
714
|
+
}));
|
|
715
|
+
mapsRelations = relations(maps, ({ many }) => ({
|
|
716
|
+
elements: many(mapElements)
|
|
717
|
+
}));
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
// ../data/src/domains/game/table.ts
|
|
721
|
+
import {
|
|
722
|
+
jsonb as jsonb2,
|
|
723
|
+
pgEnum as pgEnum3,
|
|
724
|
+
pgTable as pgTable4,
|
|
725
|
+
text as text4,
|
|
726
|
+
timestamp as timestamp3,
|
|
727
|
+
uniqueIndex as uniqueIndex3,
|
|
728
|
+
uuid as uuid3,
|
|
729
|
+
varchar as varchar3
|
|
730
|
+
} from "drizzle-orm/pg-core";
|
|
731
|
+
var gamePlatformEnum, gameBootModeEnum, games, gameSessions, gameStates;
|
|
732
|
+
var init_table4 = __esm(() => {
|
|
733
|
+
init_table3();
|
|
734
|
+
init_table();
|
|
735
|
+
gamePlatformEnum = pgEnum3("game_platform", ["web", "godot", "unity"]);
|
|
736
|
+
gameBootModeEnum = pgEnum3("game_boot_mode", ["iframe", "module"]);
|
|
737
|
+
games = pgTable4("games", {
|
|
738
|
+
id: uuid3("id").primaryKey().defaultRandom(),
|
|
739
|
+
developerId: text4("developer_id").references(() => users.id, {
|
|
740
|
+
onDelete: "set null"
|
|
741
|
+
}),
|
|
742
|
+
slug: varchar3("slug", { length: 255 }).notNull().unique(),
|
|
743
|
+
displayName: varchar3("display_name", { length: 255 }).notNull(),
|
|
744
|
+
version: varchar3("version", { length: 50 }).notNull(),
|
|
745
|
+
assetBundleBase: text4("asset_bundle_base").notNull(),
|
|
746
|
+
platform: gamePlatformEnum("platform").notNull().default("web"),
|
|
747
|
+
mapElementId: uuid3("map_element_id").references(() => mapElements.id, {
|
|
748
|
+
onDelete: "set null"
|
|
749
|
+
}),
|
|
750
|
+
metadata: jsonb2("metadata").default("{}"),
|
|
751
|
+
createdAt: timestamp3("created_at", { withTimezone: true }).defaultNow(),
|
|
752
|
+
updatedAt: timestamp3("updated_at", { withTimezone: true }).defaultNow()
|
|
753
|
+
});
|
|
754
|
+
gameSessions = pgTable4("game_sessions", {
|
|
755
|
+
id: uuid3("id").primaryKey().defaultRandom(),
|
|
756
|
+
userId: text4("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
757
|
+
gameId: uuid3("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
|
|
758
|
+
startedAt: timestamp3("started_at", { withTimezone: true }).notNull().defaultNow(),
|
|
759
|
+
endedAt: timestamp3("ended_at", { withTimezone: true })
|
|
760
|
+
});
|
|
761
|
+
gameStates = pgTable4("game_states", {
|
|
762
|
+
userId: text4("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
763
|
+
gameId: uuid3("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
|
|
764
|
+
data: jsonb2("data").default("{}"),
|
|
765
|
+
updatedAt: timestamp3("updated_at", { withTimezone: true }).defaultNow()
|
|
766
|
+
}, (table) => [uniqueIndex3("unique_user_game_idx").on(table.userId, table.gameId)]);
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
// ../data/src/domains/inventory/table.ts
|
|
770
|
+
import { relations as relations2, sql } from "drizzle-orm";
|
|
771
|
+
import {
|
|
772
|
+
boolean as boolean2,
|
|
773
|
+
integer,
|
|
774
|
+
jsonb as jsonb3,
|
|
775
|
+
pgEnum as pgEnum4,
|
|
776
|
+
pgTable as pgTable5,
|
|
777
|
+
text as text5,
|
|
778
|
+
timestamp as timestamp4,
|
|
779
|
+
uniqueIndex as uniqueIndex4,
|
|
780
|
+
uuid as uuid4
|
|
781
|
+
} from "drizzle-orm/pg-core";
|
|
782
|
+
var itemTypeEnum, items, inventoryItems, currencies, shopListings, itemsRelations, currenciesRelations, shopListingsRelations, inventoryItemsRelations;
|
|
783
|
+
var init_table5 = __esm(() => {
|
|
784
|
+
init_table4();
|
|
785
|
+
init_table();
|
|
786
|
+
itemTypeEnum = pgEnum4("item_type", [
|
|
787
|
+
"currency",
|
|
788
|
+
"badge",
|
|
789
|
+
"trophy",
|
|
790
|
+
"collectible",
|
|
791
|
+
"consumable",
|
|
792
|
+
"unlock",
|
|
793
|
+
"upgrade",
|
|
794
|
+
"other"
|
|
795
|
+
]);
|
|
796
|
+
items = pgTable5("items", {
|
|
797
|
+
id: uuid4("id").primaryKey().defaultRandom(),
|
|
798
|
+
slug: text5("slug").notNull(),
|
|
799
|
+
gameId: uuid4("game_id").references(() => games.id, {
|
|
800
|
+
onDelete: "cascade"
|
|
801
|
+
}),
|
|
802
|
+
displayName: text5("display_name").notNull(),
|
|
803
|
+
description: text5("description"),
|
|
804
|
+
type: itemTypeEnum("type").notNull().default("other"),
|
|
805
|
+
imageUrl: text5("image_url"),
|
|
806
|
+
metadata: jsonb3("metadata").default({}),
|
|
807
|
+
createdAt: timestamp4("created_at").defaultNow().notNull()
|
|
808
|
+
}, (table) => [
|
|
809
|
+
uniqueIndex4("items_game_slug_idx").on(table.gameId, table.slug),
|
|
810
|
+
uniqueIndex4("items_global_slug_idx").on(table.slug).where(sql`game_id IS NULL`)
|
|
811
|
+
]);
|
|
812
|
+
inventoryItems = pgTable5("inventory_items", {
|
|
813
|
+
id: uuid4("id").primaryKey().defaultRandom(),
|
|
814
|
+
userId: text5("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
815
|
+
itemId: uuid4("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
|
|
816
|
+
quantity: integer("quantity").notNull().default(1),
|
|
817
|
+
updatedAt: timestamp4("updated_at", { withTimezone: true }).defaultNow()
|
|
818
|
+
}, (table) => [uniqueIndex4("unique_user_item_idx").on(table.userId, table.itemId)]);
|
|
819
|
+
currencies = pgTable5("currencies", {
|
|
820
|
+
id: uuid4("id").primaryKey().defaultRandom(),
|
|
821
|
+
itemId: uuid4("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
|
|
822
|
+
symbol: text5("symbol"),
|
|
823
|
+
isPrimary: boolean2("is_primary").default(false).notNull(),
|
|
824
|
+
createdAt: timestamp4("created_at").defaultNow().notNull(),
|
|
825
|
+
updatedAt: timestamp4("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
|
|
826
|
+
}, (table) => [uniqueIndex4("currency_item_id_idx").on(table.itemId)]);
|
|
827
|
+
shopListings = pgTable5("shop_listings", {
|
|
828
|
+
id: uuid4("id").primaryKey().defaultRandom(),
|
|
829
|
+
itemId: uuid4("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
|
|
830
|
+
currencyId: uuid4("currency_id").notNull().references(() => currencies.id, { onDelete: "restrict" }),
|
|
831
|
+
price: integer("price").notNull(),
|
|
832
|
+
sellBackPercentage: integer("sell_back_percentage"),
|
|
833
|
+
stock: integer("stock"),
|
|
834
|
+
isActive: boolean2("is_active").default(true).notNull(),
|
|
835
|
+
availableFrom: timestamp4("available_from", { withTimezone: true }),
|
|
836
|
+
availableUntil: timestamp4("available_until", { withTimezone: true }),
|
|
837
|
+
createdAt: timestamp4("created_at").defaultNow().notNull(),
|
|
838
|
+
updatedAt: timestamp4("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
|
|
839
|
+
}, (table) => [uniqueIndex4("unique_item_currency_listing_idx").on(table.itemId, table.currencyId)]);
|
|
840
|
+
itemsRelations = relations2(items, ({ many }) => ({
|
|
841
|
+
shopListings: many(shopListings),
|
|
842
|
+
inventoryItems: many(inventoryItems)
|
|
843
|
+
}));
|
|
844
|
+
currenciesRelations = relations2(currencies, ({ many }) => ({
|
|
845
|
+
shopListings: many(shopListings)
|
|
846
|
+
}));
|
|
847
|
+
shopListingsRelations = relations2(shopListings, ({ one }) => ({
|
|
848
|
+
item: one(items, {
|
|
849
|
+
fields: [shopListings.itemId],
|
|
850
|
+
references: [items.id]
|
|
851
|
+
}),
|
|
852
|
+
currency: one(currencies, {
|
|
853
|
+
fields: [shopListings.currencyId],
|
|
854
|
+
references: [currencies.id]
|
|
855
|
+
})
|
|
856
|
+
}));
|
|
857
|
+
inventoryItemsRelations = relations2(inventoryItems, ({ one }) => ({
|
|
858
|
+
item: one(items, {
|
|
859
|
+
fields: [inventoryItems.itemId],
|
|
860
|
+
references: [items.id]
|
|
861
|
+
}),
|
|
862
|
+
user: one(users, {
|
|
863
|
+
fields: [inventoryItems.userId],
|
|
864
|
+
references: [users.id]
|
|
865
|
+
})
|
|
866
|
+
}));
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
// ../data/src/domains/level/table.ts
|
|
870
|
+
import { relations as relations3 } from "drizzle-orm";
|
|
871
|
+
import { integer as integer2, pgTable as pgTable6, text as text6, timestamp as timestamp5, uniqueIndex as uniqueIndex5, uuid as uuid5 } from "drizzle-orm/pg-core";
|
|
872
|
+
var userLevels, levelConfigs, userLevelsRelations;
|
|
873
|
+
var init_table6 = __esm(() => {
|
|
874
|
+
init_table();
|
|
875
|
+
userLevels = pgTable6("user_levels", {
|
|
876
|
+
userId: text6("user_id").primaryKey().references(() => users.id, { onDelete: "cascade" }),
|
|
877
|
+
currentLevel: integer2("current_level").notNull().default(1),
|
|
878
|
+
currentXp: integer2("current_xp").notNull().default(0),
|
|
879
|
+
totalXP: integer2("total_xp").notNull().default(0),
|
|
880
|
+
lastLevelUpAt: timestamp5("last_level_up_at", { withTimezone: true }),
|
|
881
|
+
createdAt: timestamp5("created_at").defaultNow().notNull(),
|
|
882
|
+
updatedAt: timestamp5("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
|
|
883
|
+
});
|
|
884
|
+
levelConfigs = pgTable6("level_configs", {
|
|
885
|
+
id: uuid5("id").primaryKey().defaultRandom(),
|
|
886
|
+
level: integer2("level").notNull().unique(),
|
|
887
|
+
xpRequired: integer2("xp_required").notNull(),
|
|
888
|
+
creditsReward: integer2("credits_reward").notNull().default(0),
|
|
889
|
+
createdAt: timestamp5("created_at").defaultNow().notNull()
|
|
890
|
+
}, (table) => [uniqueIndex5("unique_level_config_idx").on(table.level)]);
|
|
891
|
+
userLevelsRelations = relations3(userLevels, ({ one }) => ({
|
|
892
|
+
user: one(users, {
|
|
893
|
+
fields: [userLevels.userId],
|
|
894
|
+
references: [users.id]
|
|
895
|
+
})
|
|
896
|
+
}));
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
// ../data/src/tables.index.ts
|
|
900
|
+
var init_tables_index = __esm(() => {
|
|
901
|
+
init_table();
|
|
902
|
+
init_table2();
|
|
903
|
+
init_table4();
|
|
904
|
+
init_table5();
|
|
905
|
+
init_table3();
|
|
906
|
+
init_table6();
|
|
907
|
+
});
|
|
908
|
+
|
|
440
909
|
// ../data/src/constants.ts
|
|
441
|
-
var
|
|
910
|
+
var ITEM_SLUGS, CURRENCIES, BADGES, INTERACTION_TYPE;
|
|
442
911
|
var init_constants = __esm(() => {
|
|
443
|
-
|
|
912
|
+
init_tables_index();
|
|
913
|
+
ITEM_SLUGS = {
|
|
444
914
|
PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
|
|
445
915
|
PLAYCADEMY_XP: "PLAYCADEMY_XP",
|
|
446
916
|
FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
|
|
@@ -451,14 +921,15 @@ var init_constants = __esm(() => {
|
|
|
451
921
|
SMALL_BACKPACK: "SMALL_BACKPACK"
|
|
452
922
|
};
|
|
453
923
|
CURRENCIES = {
|
|
454
|
-
PRIMARY:
|
|
455
|
-
XP:
|
|
924
|
+
PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
|
|
925
|
+
XP: ITEM_SLUGS.PLAYCADEMY_XP
|
|
456
926
|
};
|
|
457
927
|
BADGES = {
|
|
458
|
-
FOUNDING_MEMBER:
|
|
459
|
-
EARLY_ADOPTER:
|
|
460
|
-
FIRST_GAME:
|
|
928
|
+
FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
|
|
929
|
+
EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
|
|
930
|
+
FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
|
|
461
931
|
};
|
|
932
|
+
INTERACTION_TYPE = Object.fromEntries(interactionTypeEnum.enumValues.map((value) => [value, value]));
|
|
462
933
|
});
|
|
463
934
|
|
|
464
935
|
// src/core/namespaces/credits.ts
|
|
@@ -468,9 +939,9 @@ function createCreditsNamespace(client) {
|
|
|
468
939
|
if (cachedCreditsItemId) {
|
|
469
940
|
return cachedCreditsItemId;
|
|
470
941
|
}
|
|
471
|
-
const
|
|
472
|
-
const creditsItem = items.
|
|
473
|
-
if (!creditsItem) {
|
|
942
|
+
const queryParams = new URLSearchParams({ slug: CURRENCIES.PRIMARY });
|
|
943
|
+
const creditsItem = await client["request"](`/items/resolve?${queryParams.toString()}`, "GET");
|
|
944
|
+
if (!creditsItem || !creditsItem.id) {
|
|
474
945
|
throw new Error("Playcademy Credits item not found in catalog");
|
|
475
946
|
}
|
|
476
947
|
cachedCreditsItemId = creditsItem.id;
|
|
@@ -479,8 +950,8 @@ function createCreditsNamespace(client) {
|
|
|
479
950
|
return {
|
|
480
951
|
balance: async () => {
|
|
481
952
|
const inventory = await client.users.inventory.get();
|
|
482
|
-
const
|
|
483
|
-
return
|
|
953
|
+
const primaryCurrencyInventoryItem = inventory.find((item) => item.item?.slug === CURRENCIES.PRIMARY);
|
|
954
|
+
return primaryCurrencyInventoryItem?.quantity ?? 0;
|
|
484
955
|
},
|
|
485
956
|
add: async (amount) => {
|
|
486
957
|
if (amount <= 0) {
|
|
@@ -606,13 +1077,14 @@ async function login(baseUrl, email, password) {
|
|
|
606
1077
|
const errorMessage = errorData && errorData.message ? String(errorData.message) : response.statusText;
|
|
607
1078
|
throw new PlaycademyError(errorMessage);
|
|
608
1079
|
} catch (error) {
|
|
609
|
-
|
|
1080
|
+
log.error("[Playcademy SDK] Failed to parse error response JSON, using status text instead:", { error });
|
|
610
1081
|
throw new PlaycademyError(response.statusText);
|
|
611
1082
|
}
|
|
612
1083
|
}
|
|
613
1084
|
return response.json();
|
|
614
1085
|
}
|
|
615
1086
|
var init_login = __esm(() => {
|
|
1087
|
+
init_src();
|
|
616
1088
|
init_errors();
|
|
617
1089
|
});
|
|
618
1090
|
|
|
@@ -629,9 +1101,10 @@ __export(exports_client, {
|
|
|
629
1101
|
});
|
|
630
1102
|
var PlaycademyClient;
|
|
631
1103
|
var init_client = __esm(() => {
|
|
1104
|
+
init_src();
|
|
632
1105
|
init_errors();
|
|
633
|
-
init_request();
|
|
634
1106
|
init_namespaces();
|
|
1107
|
+
init_request();
|
|
635
1108
|
init_static();
|
|
636
1109
|
PlaycademyClient = class PlaycademyClient {
|
|
637
1110
|
baseUrl;
|
|
@@ -651,14 +1124,16 @@ var init_client = __esm(() => {
|
|
|
651
1124
|
}
|
|
652
1125
|
if (this.gameId) {
|
|
653
1126
|
this._initializeInternalSession().catch((error) => {
|
|
654
|
-
|
|
1127
|
+
log.error("[Playcademy SDK] Background initialization of auto-session failed:", {
|
|
1128
|
+
error
|
|
1129
|
+
});
|
|
655
1130
|
});
|
|
656
1131
|
}
|
|
657
1132
|
}
|
|
658
1133
|
getBaseUrl() {
|
|
659
1134
|
const isRelative = this.baseUrl.startsWith("/");
|
|
660
|
-
const
|
|
661
|
-
return isRelative &&
|
|
1135
|
+
const isBrowser2 = typeof window !== "undefined";
|
|
1136
|
+
return isRelative && isBrowser2 ? `${window.location.origin}${this.baseUrl}` : this.baseUrl;
|
|
662
1137
|
}
|
|
663
1138
|
ping() {
|
|
664
1139
|
return "pong";
|
|
@@ -704,7 +1179,10 @@ var init_client = __esm(() => {
|
|
|
704
1179
|
const response = await this.games.startSession(this.gameId);
|
|
705
1180
|
this.internalClientSessionId = response.sessionId;
|
|
706
1181
|
} catch (error) {
|
|
707
|
-
|
|
1182
|
+
log.error("[Playcademy SDK] Auto-starting session failed for game", {
|
|
1183
|
+
gameId: this.gameId,
|
|
1184
|
+
error
|
|
1185
|
+
});
|
|
708
1186
|
}
|
|
709
1187
|
}
|
|
710
1188
|
auth = createAuthNamespace(this);
|