playcademy 0.14.32 → 0.14.33
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/cli.js +215 -10
- package/dist/constants/src/achievements.ts +107 -0
- package/dist/constants/src/character.ts +16 -0
- package/dist/constants/src/index.ts +3 -0
- package/dist/constants/src/timeback.ts +9 -0
- package/dist/constants/src/typescript.ts +19 -0
- package/dist/constants.js +99 -1
- package/dist/db.d.ts +68 -20
- package/dist/db.js +459 -43
- package/dist/edge-play/src/routes/integrations/timeback/end-activity.ts +1 -1
- package/dist/edge-play/src/types.ts +1 -1
- package/dist/index.d.ts +248 -16
- package/dist/index.js +957 -128
- package/dist/utils.d.ts +198 -8
- package/dist/utils.js +148 -34
- package/dist/version.js +2 -1
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -562,17 +562,11 @@ function displayApiError(error, indent) {
|
|
|
562
562
|
return;
|
|
563
563
|
}
|
|
564
564
|
const statusCode = errorInfo.status;
|
|
565
|
-
let displayMessage = errorInfo.
|
|
565
|
+
let displayMessage = errorInfo.message;
|
|
566
566
|
displayMessage = removeStatusPrefix(displayMessage, statusCode);
|
|
567
567
|
const { cleanMessage, json: embeddedJson } = extractEmbeddedJson(displayMessage);
|
|
568
568
|
displayMessage = cleanMessageSuffix(cleanMessage);
|
|
569
|
-
|
|
570
|
-
if (error.details && typeof error.details === "object") {
|
|
571
|
-
const details = error.details;
|
|
572
|
-
if ("code" in details && typeof details.code === "string") {
|
|
573
|
-
errorCode = details.code;
|
|
574
|
-
}
|
|
575
|
-
}
|
|
569
|
+
const errorCode = error.code;
|
|
576
570
|
let errorHeader = "API Error";
|
|
577
571
|
if (errorCode) {
|
|
578
572
|
errorHeader += ` ${redBright(`[${errorCode}]`)}`;
|
|
@@ -1050,7 +1044,7 @@ var package_default = {
|
|
|
1050
1044
|
sort: "bunx sort-package-json **/package.json",
|
|
1051
1045
|
test: "bun test",
|
|
1052
1046
|
"test:unit": "bun scripts/test-unit.ts",
|
|
1053
|
-
"test:
|
|
1047
|
+
"test:e2e": "bun scripts/test-e2e.ts",
|
|
1054
1048
|
"test:watch": "bun test --watch",
|
|
1055
1049
|
"docker:relay": "bun run scripts/docker-relay.ts",
|
|
1056
1050
|
"debug:leaderboard-notifications": "bunx sst shell -- bun scripts/debug/leaderboard-notifications.ts",
|
|
@@ -1210,6 +1204,104 @@ var CONFIG_FILE_NAMES = [
|
|
|
1210
1204
|
"playcademy.config.mjs"
|
|
1211
1205
|
];
|
|
1212
1206
|
|
|
1207
|
+
// ../constants/src/achievements.ts
|
|
1208
|
+
var ACHIEVEMENT_IDS = {
|
|
1209
|
+
PLAY_ANY_GAME_DAILY: "play_any_game_daily",
|
|
1210
|
+
DAILY_CHEST_OPEN: "daily_chest_open",
|
|
1211
|
+
LEADERBOARD_TOP3_DAILY: "leaderboard_top3_daily",
|
|
1212
|
+
LEADERBOARD_TOP3_WEEKLY: "leaderboard_top3_weekly",
|
|
1213
|
+
FIRST_SCORE_ANY_GAME: "first_score_any_game",
|
|
1214
|
+
PERSONAL_BEST_ANY_GAME: "personal_best_any_game"
|
|
1215
|
+
};
|
|
1216
|
+
var ACHIEVEMENT_DEFINITIONS = [
|
|
1217
|
+
{
|
|
1218
|
+
id: ACHIEVEMENT_IDS.PLAY_ANY_GAME_DAILY,
|
|
1219
|
+
title: "Play any game",
|
|
1220
|
+
description: "Play any arcade game for at least 60 seconds in a single session.",
|
|
1221
|
+
scope: "daily",
|
|
1222
|
+
rewardCredits: 10,
|
|
1223
|
+
limit: 1,
|
|
1224
|
+
completionType: "time_played_session",
|
|
1225
|
+
completionConfig: { minSeconds: 60 },
|
|
1226
|
+
target: { anyArcadeGame: true },
|
|
1227
|
+
active: true
|
|
1228
|
+
},
|
|
1229
|
+
{
|
|
1230
|
+
id: ACHIEVEMENT_IDS.DAILY_CHEST_OPEN,
|
|
1231
|
+
title: "Opened the daily chest",
|
|
1232
|
+
description: "Find the chest on the map and open it to claim your reward.",
|
|
1233
|
+
scope: "daily",
|
|
1234
|
+
rewardCredits: 10,
|
|
1235
|
+
limit: 1,
|
|
1236
|
+
completionType: "interaction",
|
|
1237
|
+
completionConfig: { triggerId: "bunny_chest" },
|
|
1238
|
+
target: { map: "arcade" },
|
|
1239
|
+
active: true
|
|
1240
|
+
},
|
|
1241
|
+
{
|
|
1242
|
+
id: ACHIEVEMENT_IDS.LEADERBOARD_TOP3_DAILY,
|
|
1243
|
+
title: "Daily Champion",
|
|
1244
|
+
description: "Finish in the top 3 of any game leaderboard for the day.",
|
|
1245
|
+
scope: "daily",
|
|
1246
|
+
rewardCredits: 25,
|
|
1247
|
+
// Base reward, overridden by rankRewards
|
|
1248
|
+
limit: 1,
|
|
1249
|
+
completionType: "leaderboard_rank",
|
|
1250
|
+
completionConfig: {
|
|
1251
|
+
rankRewards: [50, 30, 15]
|
|
1252
|
+
// [1st place, 2nd place, 3rd place]
|
|
1253
|
+
},
|
|
1254
|
+
target: { anyArcadeGame: true },
|
|
1255
|
+
active: true
|
|
1256
|
+
},
|
|
1257
|
+
{
|
|
1258
|
+
id: ACHIEVEMENT_IDS.LEADERBOARD_TOP3_WEEKLY,
|
|
1259
|
+
title: "Weekly Legend",
|
|
1260
|
+
description: "Finish in the top 3 of any game leaderboard for the week.",
|
|
1261
|
+
scope: "weekly",
|
|
1262
|
+
rewardCredits: 50,
|
|
1263
|
+
// Base reward, overridden by rankRewards
|
|
1264
|
+
limit: 1,
|
|
1265
|
+
completionType: "leaderboard_rank",
|
|
1266
|
+
completionConfig: {
|
|
1267
|
+
rankRewards: [100, 60, 30]
|
|
1268
|
+
// [1st place, 2nd place, 3rd place]
|
|
1269
|
+
},
|
|
1270
|
+
target: { anyArcadeGame: true },
|
|
1271
|
+
active: true
|
|
1272
|
+
},
|
|
1273
|
+
{
|
|
1274
|
+
id: ACHIEVEMENT_IDS.FIRST_SCORE_ANY_GAME,
|
|
1275
|
+
title: "First Score",
|
|
1276
|
+
description: "Submit your first score in any arcade game.",
|
|
1277
|
+
scope: "game",
|
|
1278
|
+
// Scoped per game, no time limit
|
|
1279
|
+
rewardCredits: 5,
|
|
1280
|
+
limit: 1,
|
|
1281
|
+
completionType: "first_score",
|
|
1282
|
+
completionConfig: {},
|
|
1283
|
+
target: { anyArcadeGame: true },
|
|
1284
|
+
active: true
|
|
1285
|
+
},
|
|
1286
|
+
{
|
|
1287
|
+
id: ACHIEVEMENT_IDS.PERSONAL_BEST_ANY_GAME,
|
|
1288
|
+
title: "Personal Best",
|
|
1289
|
+
description: "Beat your personal best score in any arcade game.",
|
|
1290
|
+
scope: "daily",
|
|
1291
|
+
rewardCredits: 5,
|
|
1292
|
+
limit: 3,
|
|
1293
|
+
// Can earn 3 times per day
|
|
1294
|
+
completionType: "personal_best",
|
|
1295
|
+
completionConfig: {},
|
|
1296
|
+
target: { anyArcadeGame: true },
|
|
1297
|
+
active: true
|
|
1298
|
+
}
|
|
1299
|
+
];
|
|
1300
|
+
|
|
1301
|
+
// ../constants/src/typescript.ts
|
|
1302
|
+
var TSC_PACKAGE = "@typescript/native-preview";
|
|
1303
|
+
var USE_NATIVE_TSC = TSC_PACKAGE.includes("native-preview");
|
|
1304
|
+
|
|
1213
1305
|
// ../constants/src/overworld.ts
|
|
1214
1306
|
var ITEM_SLUGS = {
|
|
1215
1307
|
/** Primary platform currency */
|
|
@@ -1269,6 +1361,9 @@ function hasPackageJson(dir) {
|
|
|
1269
1361
|
return existsSync3(resolve2(dir || getWorkspace(), "package.json"));
|
|
1270
1362
|
}
|
|
1271
1363
|
|
|
1364
|
+
// src/lib/core/errors.ts
|
|
1365
|
+
import { ApiError as ApiError2 } from "@playcademy/sdk/internal";
|
|
1366
|
+
|
|
1272
1367
|
// src/lib/core/gitignore.ts
|
|
1273
1368
|
function normalizeGitignoreEntry(entry) {
|
|
1274
1369
|
return entry.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -1277,6 +1372,9 @@ function normalizeGitignoreEntry(entry) {
|
|
|
1277
1372
|
// src/lib/core/import.ts
|
|
1278
1373
|
import * as esbuild from "esbuild";
|
|
1279
1374
|
|
|
1375
|
+
// src/lib/core/transpile.ts
|
|
1376
|
+
import * as esbuild2 from "esbuild";
|
|
1377
|
+
|
|
1280
1378
|
// src/lib/secrets/env.ts
|
|
1281
1379
|
init_file_loader();
|
|
1282
1380
|
import { existsSync as existsSync4, writeFileSync } from "fs";
|
|
@@ -1628,8 +1726,105 @@ function processConfigVariables(config) {
|
|
|
1628
1726
|
|
|
1629
1727
|
// ../timeback/dist/constants.js
|
|
1630
1728
|
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
1729
|
+
var ACHIEVEMENT_IDS2;
|
|
1730
|
+
var ACHIEVEMENT_DEFINITIONS2;
|
|
1731
|
+
var init_achievements = __esm2(() => {
|
|
1732
|
+
ACHIEVEMENT_IDS2 = {
|
|
1733
|
+
PLAY_ANY_GAME_DAILY: "play_any_game_daily",
|
|
1734
|
+
DAILY_CHEST_OPEN: "daily_chest_open",
|
|
1735
|
+
LEADERBOARD_TOP3_DAILY: "leaderboard_top3_daily",
|
|
1736
|
+
LEADERBOARD_TOP3_WEEKLY: "leaderboard_top3_weekly",
|
|
1737
|
+
FIRST_SCORE_ANY_GAME: "first_score_any_game",
|
|
1738
|
+
PERSONAL_BEST_ANY_GAME: "personal_best_any_game"
|
|
1739
|
+
};
|
|
1740
|
+
ACHIEVEMENT_DEFINITIONS2 = [
|
|
1741
|
+
{
|
|
1742
|
+
id: ACHIEVEMENT_IDS2.PLAY_ANY_GAME_DAILY,
|
|
1743
|
+
title: "Play any game",
|
|
1744
|
+
description: "Play any arcade game for at least 60 seconds in a single session.",
|
|
1745
|
+
scope: "daily",
|
|
1746
|
+
rewardCredits: 10,
|
|
1747
|
+
limit: 1,
|
|
1748
|
+
completionType: "time_played_session",
|
|
1749
|
+
completionConfig: { minSeconds: 60 },
|
|
1750
|
+
target: { anyArcadeGame: true },
|
|
1751
|
+
active: true
|
|
1752
|
+
},
|
|
1753
|
+
{
|
|
1754
|
+
id: ACHIEVEMENT_IDS2.DAILY_CHEST_OPEN,
|
|
1755
|
+
title: "Opened the daily chest",
|
|
1756
|
+
description: "Find the chest on the map and open it to claim your reward.",
|
|
1757
|
+
scope: "daily",
|
|
1758
|
+
rewardCredits: 10,
|
|
1759
|
+
limit: 1,
|
|
1760
|
+
completionType: "interaction",
|
|
1761
|
+
completionConfig: { triggerId: "bunny_chest" },
|
|
1762
|
+
target: { map: "arcade" },
|
|
1763
|
+
active: true
|
|
1764
|
+
},
|
|
1765
|
+
{
|
|
1766
|
+
id: ACHIEVEMENT_IDS2.LEADERBOARD_TOP3_DAILY,
|
|
1767
|
+
title: "Daily Champion",
|
|
1768
|
+
description: "Finish in the top 3 of any game leaderboard for the day.",
|
|
1769
|
+
scope: "daily",
|
|
1770
|
+
rewardCredits: 25,
|
|
1771
|
+
limit: 1,
|
|
1772
|
+
completionType: "leaderboard_rank",
|
|
1773
|
+
completionConfig: {
|
|
1774
|
+
rankRewards: [50, 30, 15]
|
|
1775
|
+
},
|
|
1776
|
+
target: { anyArcadeGame: true },
|
|
1777
|
+
active: true
|
|
1778
|
+
},
|
|
1779
|
+
{
|
|
1780
|
+
id: ACHIEVEMENT_IDS2.LEADERBOARD_TOP3_WEEKLY,
|
|
1781
|
+
title: "Weekly Legend",
|
|
1782
|
+
description: "Finish in the top 3 of any game leaderboard for the week.",
|
|
1783
|
+
scope: "weekly",
|
|
1784
|
+
rewardCredits: 50,
|
|
1785
|
+
limit: 1,
|
|
1786
|
+
completionType: "leaderboard_rank",
|
|
1787
|
+
completionConfig: {
|
|
1788
|
+
rankRewards: [100, 60, 30]
|
|
1789
|
+
},
|
|
1790
|
+
target: { anyArcadeGame: true },
|
|
1791
|
+
active: true
|
|
1792
|
+
},
|
|
1793
|
+
{
|
|
1794
|
+
id: ACHIEVEMENT_IDS2.FIRST_SCORE_ANY_GAME,
|
|
1795
|
+
title: "First Score",
|
|
1796
|
+
description: "Submit your first score in any arcade game.",
|
|
1797
|
+
scope: "game",
|
|
1798
|
+
rewardCredits: 5,
|
|
1799
|
+
limit: 1,
|
|
1800
|
+
completionType: "first_score",
|
|
1801
|
+
completionConfig: {},
|
|
1802
|
+
target: { anyArcadeGame: true },
|
|
1803
|
+
active: true
|
|
1804
|
+
},
|
|
1805
|
+
{
|
|
1806
|
+
id: ACHIEVEMENT_IDS2.PERSONAL_BEST_ANY_GAME,
|
|
1807
|
+
title: "Personal Best",
|
|
1808
|
+
description: "Beat your personal best score in any arcade game.",
|
|
1809
|
+
scope: "daily",
|
|
1810
|
+
rewardCredits: 5,
|
|
1811
|
+
limit: 3,
|
|
1812
|
+
completionType: "personal_best",
|
|
1813
|
+
completionConfig: {},
|
|
1814
|
+
target: { anyArcadeGame: true },
|
|
1815
|
+
active: true
|
|
1816
|
+
}
|
|
1817
|
+
];
|
|
1818
|
+
});
|
|
1631
1819
|
var init_auth = () => {
|
|
1632
1820
|
};
|
|
1821
|
+
var TSC_PACKAGE2 = "@typescript/native-preview";
|
|
1822
|
+
var USE_NATIVE_TSC2;
|
|
1823
|
+
var init_typescript = __esm2(() => {
|
|
1824
|
+
USE_NATIVE_TSC2 = TSC_PACKAGE2.includes("native-preview");
|
|
1825
|
+
});
|
|
1826
|
+
var init_character = () => {
|
|
1827
|
+
};
|
|
1633
1828
|
var PLAYCADEMY_BASE_URLS2;
|
|
1634
1829
|
var init_domains = __esm2(() => {
|
|
1635
1830
|
PLAYCADEMY_BASE_URLS2 = {
|
|
@@ -1666,6 +1861,7 @@ var init_overworld = __esm2(() => {
|
|
|
1666
1861
|
FIRST_GAME: ITEM_SLUGS2.FIRST_GAME_BADGE
|
|
1667
1862
|
};
|
|
1668
1863
|
});
|
|
1864
|
+
var TIMEBACK_CALIPER_SENSORS;
|
|
1669
1865
|
var TIMEBACK_ORG_SOURCED_ID = "PLAYCADEMY";
|
|
1670
1866
|
var TIMEBACK_ORG_NAME = "Playcademy Studios";
|
|
1671
1867
|
var TIMEBACK_ORG_TYPE = "department";
|
|
@@ -1674,6 +1870,11 @@ var TIMEBACK_RESOURCE_DEFAULTS;
|
|
|
1674
1870
|
var TIMEBACK_COMPONENT_DEFAULTS;
|
|
1675
1871
|
var TIMEBACK_COMPONENT_RESOURCE_DEFAULTS;
|
|
1676
1872
|
var init_timeback = __esm2(() => {
|
|
1873
|
+
TIMEBACK_CALIPER_SENSORS = [
|
|
1874
|
+
"https://samuraimath.com",
|
|
1875
|
+
"https://app.alphamath.school",
|
|
1876
|
+
"https://mathraiders.com"
|
|
1877
|
+
];
|
|
1677
1878
|
TIMEBACK_COURSE_DEFAULTS = {
|
|
1678
1879
|
gradingScheme: "STANDARD",
|
|
1679
1880
|
level: {
|
|
@@ -1714,7 +1915,10 @@ var init_timeback = __esm2(() => {
|
|
|
1714
1915
|
var init_workers = () => {
|
|
1715
1916
|
};
|
|
1716
1917
|
var init_src = __esm2(() => {
|
|
1918
|
+
init_achievements();
|
|
1717
1919
|
init_auth();
|
|
1920
|
+
init_typescript();
|
|
1921
|
+
init_character();
|
|
1718
1922
|
init_domains();
|
|
1719
1923
|
init_env_vars();
|
|
1720
1924
|
init_overworld();
|
|
@@ -2754,7 +2958,7 @@ import { join as join13 } from "path";
|
|
|
2754
2958
|
// package.json with { type: 'json' }
|
|
2755
2959
|
var package_default2 = {
|
|
2756
2960
|
name: "playcademy",
|
|
2757
|
-
version: "0.14.
|
|
2961
|
+
version: "0.14.32",
|
|
2758
2962
|
type: "module",
|
|
2759
2963
|
exports: {
|
|
2760
2964
|
".": {
|
|
@@ -2798,6 +3002,7 @@ var package_default2 = {
|
|
|
2798
3002
|
],
|
|
2799
3003
|
scripts: {
|
|
2800
3004
|
build: "bun build.ts",
|
|
3005
|
+
check: "bunx @typescript/native-preview --noEmit",
|
|
2801
3006
|
dev: "PLAYCADEMY_BASE_URL=http://localhost:5174 bun src/index.ts",
|
|
2802
3007
|
pub: "bun publish.ts"
|
|
2803
3008
|
},
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Achievement definitions - single source of truth for all achievements
|
|
3
|
+
*
|
|
4
|
+
* Used by:
|
|
5
|
+
* - apps/cademy seed scripts
|
|
6
|
+
* - packages/sandbox seeding
|
|
7
|
+
* - packages/fns achievement awarding
|
|
8
|
+
*
|
|
9
|
+
* NOTE: Uses string literals instead of AchievementCompletionType enum
|
|
10
|
+
* to avoid circular dependency with @playcademy/data
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Achievement IDs as constants to avoid magic strings
|
|
15
|
+
*/
|
|
16
|
+
export const ACHIEVEMENT_IDS = {
|
|
17
|
+
PLAY_ANY_GAME_DAILY: 'play_any_game_daily',
|
|
18
|
+
DAILY_CHEST_OPEN: 'daily_chest_open',
|
|
19
|
+
LEADERBOARD_TOP3_DAILY: 'leaderboard_top3_daily',
|
|
20
|
+
LEADERBOARD_TOP3_WEEKLY: 'leaderboard_top3_weekly',
|
|
21
|
+
FIRST_SCORE_ANY_GAME: 'first_score_any_game',
|
|
22
|
+
PERSONAL_BEST_ANY_GAME: 'personal_best_any_game',
|
|
23
|
+
} as const
|
|
24
|
+
|
|
25
|
+
export type AchievementId = (typeof ACHIEVEMENT_IDS)[keyof typeof ACHIEVEMENT_IDS]
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Achievement definitions for platform seeding
|
|
29
|
+
*/
|
|
30
|
+
export const ACHIEVEMENT_DEFINITIONS = [
|
|
31
|
+
{
|
|
32
|
+
id: ACHIEVEMENT_IDS.PLAY_ANY_GAME_DAILY,
|
|
33
|
+
title: 'Play any game',
|
|
34
|
+
description: 'Play any arcade game for at least 60 seconds in a single session.',
|
|
35
|
+
scope: 'daily' as const,
|
|
36
|
+
rewardCredits: 10,
|
|
37
|
+
limit: 1,
|
|
38
|
+
completionType: 'time_played_session' as const,
|
|
39
|
+
completionConfig: { minSeconds: 60 },
|
|
40
|
+
target: { anyArcadeGame: true },
|
|
41
|
+
active: true,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: ACHIEVEMENT_IDS.DAILY_CHEST_OPEN,
|
|
45
|
+
title: 'Opened the daily chest',
|
|
46
|
+
description: 'Find the chest on the map and open it to claim your reward.',
|
|
47
|
+
scope: 'daily' as const,
|
|
48
|
+
rewardCredits: 10,
|
|
49
|
+
limit: 1,
|
|
50
|
+
completionType: 'interaction' as const,
|
|
51
|
+
completionConfig: { triggerId: 'bunny_chest' },
|
|
52
|
+
target: { map: 'arcade' },
|
|
53
|
+
active: true,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: ACHIEVEMENT_IDS.LEADERBOARD_TOP3_DAILY,
|
|
57
|
+
title: 'Daily Champion',
|
|
58
|
+
description: 'Finish in the top 3 of any game leaderboard for the day.',
|
|
59
|
+
scope: 'daily' as const,
|
|
60
|
+
rewardCredits: 25, // Base reward, overridden by rankRewards
|
|
61
|
+
limit: 1,
|
|
62
|
+
completionType: 'leaderboard_rank' as const,
|
|
63
|
+
completionConfig: {
|
|
64
|
+
rankRewards: [50, 30, 15], // [1st place, 2nd place, 3rd place]
|
|
65
|
+
},
|
|
66
|
+
target: { anyArcadeGame: true },
|
|
67
|
+
active: true,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: ACHIEVEMENT_IDS.LEADERBOARD_TOP3_WEEKLY,
|
|
71
|
+
title: 'Weekly Legend',
|
|
72
|
+
description: 'Finish in the top 3 of any game leaderboard for the week.',
|
|
73
|
+
scope: 'weekly' as const,
|
|
74
|
+
rewardCredits: 50, // Base reward, overridden by rankRewards
|
|
75
|
+
limit: 1,
|
|
76
|
+
completionType: 'leaderboard_rank' as const,
|
|
77
|
+
completionConfig: {
|
|
78
|
+
rankRewards: [100, 60, 30], // [1st place, 2nd place, 3rd place]
|
|
79
|
+
},
|
|
80
|
+
target: { anyArcadeGame: true },
|
|
81
|
+
active: true,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: ACHIEVEMENT_IDS.FIRST_SCORE_ANY_GAME,
|
|
85
|
+
title: 'First Score',
|
|
86
|
+
description: 'Submit your first score in any arcade game.',
|
|
87
|
+
scope: 'game' as const, // Scoped per game, no time limit
|
|
88
|
+
rewardCredits: 5,
|
|
89
|
+
limit: 1,
|
|
90
|
+
completionType: 'first_score' as const,
|
|
91
|
+
completionConfig: {},
|
|
92
|
+
target: { anyArcadeGame: true },
|
|
93
|
+
active: true,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: ACHIEVEMENT_IDS.PERSONAL_BEST_ANY_GAME,
|
|
97
|
+
title: 'Personal Best',
|
|
98
|
+
description: 'Beat your personal best score in any arcade game.',
|
|
99
|
+
scope: 'daily' as const,
|
|
100
|
+
rewardCredits: 5,
|
|
101
|
+
limit: 3, // Can earn 3 times per day
|
|
102
|
+
completionType: 'personal_best' as const,
|
|
103
|
+
completionConfig: {},
|
|
104
|
+
target: { anyArcadeGame: true },
|
|
105
|
+
active: true,
|
|
106
|
+
},
|
|
107
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Character Constants
|
|
3
|
+
*
|
|
4
|
+
* Configuration for player character customization.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Accessory slot configuration with unlock levels */
|
|
8
|
+
export const ACCESSORY_SLOTS = [
|
|
9
|
+
{ type: 'head', unlockLevel: 1, displayName: 'Head', maxItems: 1 },
|
|
10
|
+
{ type: 'face', unlockLevel: 2, displayName: 'Face', maxItems: 1 },
|
|
11
|
+
{ type: 'hands', unlockLevel: 10, displayName: 'Hands', maxItems: 1 },
|
|
12
|
+
{ type: 'back', unlockLevel: 15, displayName: 'Back', maxItems: 1 },
|
|
13
|
+
] as const
|
|
14
|
+
|
|
15
|
+
/** Valid accessory slot types */
|
|
16
|
+
export const VALID_SLOT_TYPES = ['head', 'face', 'hands', 'back'] as const
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* and other constants that need to be consistent across multiple packages.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
export * from './achievements'
|
|
9
10
|
export * from './auth'
|
|
11
|
+
export * from './typescript'
|
|
12
|
+
export * from './character'
|
|
10
13
|
export * from './domains'
|
|
11
14
|
export * from './env-vars'
|
|
12
15
|
export * from './overworld'
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
* Constants related to TimeBack Caliper integration.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* TimeBack LTI issuer URLs by environment
|
|
9
|
+
* Used for JWT token verification (iss claim)
|
|
10
|
+
*/
|
|
11
|
+
export const TIMEBACK_LTI_ISSUER_URLS = {
|
|
12
|
+
production: 'https://timeback.com',
|
|
13
|
+
staging: 'https://staging.timeback.com',
|
|
14
|
+
} as const
|
|
15
|
+
|
|
7
16
|
/**
|
|
8
17
|
* TimeBack Caliper sensor URLs
|
|
9
18
|
* Allowed sensor URLs for Caliper event validation
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript configuration constants
|
|
3
|
+
*
|
|
4
|
+
* Toggle between TypeScript compilers for type generation.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* TypeScript package to use for type generation via bunx.
|
|
9
|
+
*
|
|
10
|
+
* Options:
|
|
11
|
+
* - '@typescript/native-preview' - Native TypeScript compiler (faster)
|
|
12
|
+
* - 'typescript' - Standard TypeScript compiler
|
|
13
|
+
*/
|
|
14
|
+
export const TSC_PACKAGE = '@typescript/native-preview'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Whether using the native TypeScript compiler.
|
|
18
|
+
*/
|
|
19
|
+
export const USE_NATIVE_TSC = TSC_PACKAGE.includes('native-preview')
|
package/dist/constants.js
CHANGED
|
@@ -72,7 +72,7 @@ var package_default = {
|
|
|
72
72
|
sort: "bunx sort-package-json **/package.json",
|
|
73
73
|
test: "bun test",
|
|
74
74
|
"test:unit": "bun scripts/test-unit.ts",
|
|
75
|
-
"test:
|
|
75
|
+
"test:e2e": "bun scripts/test-e2e.ts",
|
|
76
76
|
"test:watch": "bun test --watch",
|
|
77
77
|
"docker:relay": "bun run scripts/docker-relay.ts",
|
|
78
78
|
"debug:leaderboard-notifications": "bunx sst shell -- bun scripts/debug/leaderboard-notifications.ts",
|
|
@@ -292,6 +292,104 @@ var CONFIG_FILE_NAMES = [
|
|
|
292
292
|
"playcademy.config.mjs"
|
|
293
293
|
];
|
|
294
294
|
|
|
295
|
+
// ../constants/src/achievements.ts
|
|
296
|
+
var ACHIEVEMENT_IDS = {
|
|
297
|
+
PLAY_ANY_GAME_DAILY: "play_any_game_daily",
|
|
298
|
+
DAILY_CHEST_OPEN: "daily_chest_open",
|
|
299
|
+
LEADERBOARD_TOP3_DAILY: "leaderboard_top3_daily",
|
|
300
|
+
LEADERBOARD_TOP3_WEEKLY: "leaderboard_top3_weekly",
|
|
301
|
+
FIRST_SCORE_ANY_GAME: "first_score_any_game",
|
|
302
|
+
PERSONAL_BEST_ANY_GAME: "personal_best_any_game"
|
|
303
|
+
};
|
|
304
|
+
var ACHIEVEMENT_DEFINITIONS = [
|
|
305
|
+
{
|
|
306
|
+
id: ACHIEVEMENT_IDS.PLAY_ANY_GAME_DAILY,
|
|
307
|
+
title: "Play any game",
|
|
308
|
+
description: "Play any arcade game for at least 60 seconds in a single session.",
|
|
309
|
+
scope: "daily",
|
|
310
|
+
rewardCredits: 10,
|
|
311
|
+
limit: 1,
|
|
312
|
+
completionType: "time_played_session",
|
|
313
|
+
completionConfig: { minSeconds: 60 },
|
|
314
|
+
target: { anyArcadeGame: true },
|
|
315
|
+
active: true
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
id: ACHIEVEMENT_IDS.DAILY_CHEST_OPEN,
|
|
319
|
+
title: "Opened the daily chest",
|
|
320
|
+
description: "Find the chest on the map and open it to claim your reward.",
|
|
321
|
+
scope: "daily",
|
|
322
|
+
rewardCredits: 10,
|
|
323
|
+
limit: 1,
|
|
324
|
+
completionType: "interaction",
|
|
325
|
+
completionConfig: { triggerId: "bunny_chest" },
|
|
326
|
+
target: { map: "arcade" },
|
|
327
|
+
active: true
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
id: ACHIEVEMENT_IDS.LEADERBOARD_TOP3_DAILY,
|
|
331
|
+
title: "Daily Champion",
|
|
332
|
+
description: "Finish in the top 3 of any game leaderboard for the day.",
|
|
333
|
+
scope: "daily",
|
|
334
|
+
rewardCredits: 25,
|
|
335
|
+
// Base reward, overridden by rankRewards
|
|
336
|
+
limit: 1,
|
|
337
|
+
completionType: "leaderboard_rank",
|
|
338
|
+
completionConfig: {
|
|
339
|
+
rankRewards: [50, 30, 15]
|
|
340
|
+
// [1st place, 2nd place, 3rd place]
|
|
341
|
+
},
|
|
342
|
+
target: { anyArcadeGame: true },
|
|
343
|
+
active: true
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
id: ACHIEVEMENT_IDS.LEADERBOARD_TOP3_WEEKLY,
|
|
347
|
+
title: "Weekly Legend",
|
|
348
|
+
description: "Finish in the top 3 of any game leaderboard for the week.",
|
|
349
|
+
scope: "weekly",
|
|
350
|
+
rewardCredits: 50,
|
|
351
|
+
// Base reward, overridden by rankRewards
|
|
352
|
+
limit: 1,
|
|
353
|
+
completionType: "leaderboard_rank",
|
|
354
|
+
completionConfig: {
|
|
355
|
+
rankRewards: [100, 60, 30]
|
|
356
|
+
// [1st place, 2nd place, 3rd place]
|
|
357
|
+
},
|
|
358
|
+
target: { anyArcadeGame: true },
|
|
359
|
+
active: true
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
id: ACHIEVEMENT_IDS.FIRST_SCORE_ANY_GAME,
|
|
363
|
+
title: "First Score",
|
|
364
|
+
description: "Submit your first score in any arcade game.",
|
|
365
|
+
scope: "game",
|
|
366
|
+
// Scoped per game, no time limit
|
|
367
|
+
rewardCredits: 5,
|
|
368
|
+
limit: 1,
|
|
369
|
+
completionType: "first_score",
|
|
370
|
+
completionConfig: {},
|
|
371
|
+
target: { anyArcadeGame: true },
|
|
372
|
+
active: true
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
id: ACHIEVEMENT_IDS.PERSONAL_BEST_ANY_GAME,
|
|
376
|
+
title: "Personal Best",
|
|
377
|
+
description: "Beat your personal best score in any arcade game.",
|
|
378
|
+
scope: "daily",
|
|
379
|
+
rewardCredits: 5,
|
|
380
|
+
limit: 3,
|
|
381
|
+
// Can earn 3 times per day
|
|
382
|
+
completionType: "personal_best",
|
|
383
|
+
completionConfig: {},
|
|
384
|
+
target: { anyArcadeGame: true },
|
|
385
|
+
active: true
|
|
386
|
+
}
|
|
387
|
+
];
|
|
388
|
+
|
|
389
|
+
// ../constants/src/typescript.ts
|
|
390
|
+
var TSC_PACKAGE = "@typescript/native-preview";
|
|
391
|
+
var USE_NATIVE_TSC = TSC_PACKAGE.includes("native-preview");
|
|
392
|
+
|
|
295
393
|
// ../constants/src/domains.ts
|
|
296
394
|
var PLAYCADEMY_DOMAINS = {
|
|
297
395
|
/** Primary domain (hub, landing pages) */
|