horizon-mcp 1.4.0 → 1.5.0
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 +11 -8
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +14 -0
- package/dist/resources/index.js.map +1 -1
- package/dist/tools/__tests__/leaderboard.test.d.ts +2 -0
- package/dist/tools/__tests__/leaderboard.test.d.ts.map +1 -0
- package/dist/tools/__tests__/leaderboard.test.js +78 -0
- package/dist/tools/__tests__/leaderboard.test.js.map +1 -0
- package/dist/tools/admin/_utils.js +1 -1
- package/dist/tools/admin/_utils.js.map +1 -1
- package/dist/tools/admin/index.d.ts.map +1 -1
- package/dist/tools/admin/index.js +2 -0
- package/dist/tools/admin/index.js.map +1 -1
- package/dist/tools/admin/localization.d.ts +15 -0
- package/dist/tools/admin/localization.d.ts.map +1 -0
- package/dist/tools/admin/localization.js +219 -0
- package/dist/tools/admin/localization.js.map +1 -0
- package/dist/tools/admin-api-client.d.ts +1 -1
- package/dist/tools/admin-api-client.js +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/leaderboard.d.ts.map +1 -1
- package/dist/tools/leaderboard.js +21 -1
- package/dist/tools/leaderboard.js.map +1 -1
- package/dist/tools/localization.d.ts +3 -0
- package/dist/tools/localization.d.ts.map +1 -0
- package/dist/tools/localization.js +73 -0
- package/dist/tools/localization.js.map +1 -0
- package/package.json +1 -1
- package/src/resources/api/app-api.md +33 -1
- package/src/resources/docs/leaderboard.md +55 -0
- package/src/resources/docs/localization.md +169 -0
- package/src/resources/quickstart/godot.md +16 -0
- package/src/resources/quickstart/unity.md +18 -0
- package/src/resources/quickstart/unreal.md +43 -0
package/README.md
CHANGED
|
@@ -60,10 +60,11 @@ Live API tools that call the horizOn backend. Requires a valid API key.
|
|
|
60
60
|
| `horizon_signin_email` | Sign in with email and password |
|
|
61
61
|
| `horizon_signin_anonymous` | Sign in with an anonymous token |
|
|
62
62
|
| `horizon_check_auth` | Check whether a user session is still valid |
|
|
63
|
+
| `horizon_list_leaderboards` | List available leaderboard boards for multi-board calls |
|
|
63
64
|
| `horizon_submit_score` | Submit a score to the leaderboard |
|
|
64
|
-
| `horizon_get_leaderboard_top` | Get the top leaderboard entries |
|
|
65
|
-
| `horizon_get_user_rank` | Get a user's leaderboard rank |
|
|
66
|
-
| `horizon_get_leaderboard_around` | Get leaderboard entries around a user's position |
|
|
65
|
+
| `horizon_get_leaderboard_top` | Get the top leaderboard entries, optionally by board key |
|
|
66
|
+
| `horizon_get_user_rank` | Get a user's leaderboard rank, optionally by board key |
|
|
67
|
+
| `horizon_get_leaderboard_around` | Get leaderboard entries around a user's position, optionally by board key |
|
|
67
68
|
| `horizon_save_cloud_data` | Save cloud data for a user |
|
|
68
69
|
| `horizon_load_cloud_data` | Load cloud save data for a user |
|
|
69
70
|
| `horizon_get_remote_config` | Get a single remote config value by key |
|
|
@@ -96,15 +97,15 @@ Resources (documentation) work without an API key. Only the live API tools requi
|
|
|
96
97
|
|
|
97
98
|
## Admin Tools (v1.2+)
|
|
98
99
|
|
|
99
|
-
With an **Account
|
|
100
|
+
With an **Account Key** (creatable in your horizOn Dashboard -> API Keys -> Create -> **Account Key**), the MCP server exposes additional tools that let Claude manage your dashboard -- projects, remote config, news, email templates, gift codes, users, leaderboards, cloud-save data, crash reports, feedback, user logs, and SMTP.
|
|
100
101
|
|
|
101
|
-
### How to get your Account
|
|
102
|
+
### How to get your Account Key
|
|
102
103
|
|
|
103
104
|
1. Log in to your [horizOn Dashboard](https://horizon.pm/dashboard)
|
|
104
105
|
2. Navigate to **API Keys** in the sidebar
|
|
105
106
|
3. Click **Create API Key**
|
|
106
|
-
4. Select **
|
|
107
|
-
5.
|
|
107
|
+
4. Select **Account Key** as the key type
|
|
108
|
+
5. Choose whether the key can access the entire account, a single Project API Key, or selected feature groups
|
|
108
109
|
6. Click **Create** -- your key will be shown **once**. Copy it immediately.
|
|
109
110
|
7. Add the key to your MCP configuration (see Setup below)
|
|
110
111
|
|
|
@@ -131,7 +132,9 @@ Both can be set together or individually. Admin tools only register when the acc
|
|
|
131
132
|
|
|
132
133
|
### Scope
|
|
133
134
|
|
|
134
|
-
|
|
135
|
+
Account Keys inherit your account's tier (FREE/BASIC/PRO/ENTERPRISE) -- they grant no extra privileges. A key can be full-account, limited to a single Project API Key, limited to selected feature groups, or both. Platform-admin-only endpoints (Blog, Banner, System-Config) are automatically unreachable. A handful of ultra-sensitive endpoints (account deletion, credentials change, key management itself, subscription cancel) require a dashboard session and cannot be called via an Account Key.
|
|
136
|
+
|
|
137
|
+
When a key is project-scoped, the backend enforces that scope on direct HTTP calls too. Account-wide endpoints or ID-only endpoints that cannot prove project context are rejected for project-scoped keys.
|
|
135
138
|
|
|
136
139
|
### Tool Groups
|
|
137
140
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0BpE;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0BpE;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgV5D"}
|
package/dist/resources/index.js
CHANGED
|
@@ -92,6 +92,20 @@ export function registerAllResources(server) {
|
|
|
92
92
|
},
|
|
93
93
|
],
|
|
94
94
|
}));
|
|
95
|
+
// Localization
|
|
96
|
+
server.registerResource("docs-localization", "horizon://docs/localization", {
|
|
97
|
+
title: "Localization",
|
|
98
|
+
description: "Server-side localized strings across 15 languages: per-key translations, single/all fetch, available languages. SDK examples.",
|
|
99
|
+
mimeType: "text/markdown",
|
|
100
|
+
}, () => ({
|
|
101
|
+
contents: [
|
|
102
|
+
{
|
|
103
|
+
uri: "horizon://docs/localization",
|
|
104
|
+
mimeType: "text/markdown",
|
|
105
|
+
text: loadDoc("docs/localization.md"),
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
}));
|
|
95
109
|
// News
|
|
96
110
|
server.registerResource("docs-news", "horizon://docs/news", {
|
|
97
111
|
title: "News",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leaderboard.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/leaderboard.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { registerLeaderboardTools } from "../leaderboard.js";
|
|
3
|
+
vi.mock("../api-client.js", async (importOriginal) => {
|
|
4
|
+
const actual = await importOriginal();
|
|
5
|
+
return {
|
|
6
|
+
...actual,
|
|
7
|
+
createApiClientFromEnv: vi.fn(),
|
|
8
|
+
};
|
|
9
|
+
});
|
|
10
|
+
import { createApiClientFromEnv } from "../api-client.js";
|
|
11
|
+
const mockedCreateApiClient = vi.mocked(createApiClientFromEnv);
|
|
12
|
+
const registeredTools = new Map();
|
|
13
|
+
function createMockServer() {
|
|
14
|
+
return {
|
|
15
|
+
registerTool: vi.fn((name, config, handler) => {
|
|
16
|
+
registeredTools.set(name, { schema: config, handler });
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
describe("registerLeaderboardTools", () => {
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
registeredTools.clear();
|
|
23
|
+
vi.restoreAllMocks();
|
|
24
|
+
});
|
|
25
|
+
it("registers default and multi-board leaderboard tools", () => {
|
|
26
|
+
const server = createMockServer();
|
|
27
|
+
registerLeaderboardTools(server);
|
|
28
|
+
expect(registeredTools.has("horizon_list_leaderboards")).toBe(true);
|
|
29
|
+
expect(registeredTools.has("horizon_submit_score")).toBe(true);
|
|
30
|
+
expect(registeredTools.has("horizon_get_leaderboard_top")).toBe(true);
|
|
31
|
+
expect(registeredTools.has("horizon_get_user_rank")).toBe(true);
|
|
32
|
+
expect(registeredTools.has("horizon_get_leaderboard_around")).toBe(true);
|
|
33
|
+
expect(registeredTools.size).toBe(5);
|
|
34
|
+
});
|
|
35
|
+
it("lists available leaderboard boards", async () => {
|
|
36
|
+
const server = createMockServer();
|
|
37
|
+
registerLeaderboardTools(server);
|
|
38
|
+
const mockGet = vi.fn().mockResolvedValue({ boards: [], totalElements: 0 });
|
|
39
|
+
mockedCreateApiClient.mockReturnValue({ get: mockGet });
|
|
40
|
+
const { handler } = registeredTools.get("horizon_list_leaderboards");
|
|
41
|
+
await handler({});
|
|
42
|
+
expect(mockGet).toHaveBeenCalledWith("/api/v1/app/leaderboards");
|
|
43
|
+
});
|
|
44
|
+
it("submits scores to a named board", async () => {
|
|
45
|
+
const server = createMockServer();
|
|
46
|
+
registerLeaderboardTools(server);
|
|
47
|
+
const mockPost = vi.fn().mockResolvedValue({ success: true });
|
|
48
|
+
mockedCreateApiClient.mockReturnValue({ post: mockPost });
|
|
49
|
+
const { handler } = registeredTools.get("horizon_submit_score");
|
|
50
|
+
await handler({
|
|
51
|
+
userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
52
|
+
score: 1200,
|
|
53
|
+
leaderboardKey: "weekly_speed",
|
|
54
|
+
});
|
|
55
|
+
expect(mockPost).toHaveBeenCalledWith("/api/v1/app/leaderboards/weekly_speed/submit", {
|
|
56
|
+
userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
57
|
+
score: 1200,
|
|
58
|
+
leaderboardKey: "weekly_speed",
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
it("gets top scores from a named board", async () => {
|
|
62
|
+
const server = createMockServer();
|
|
63
|
+
registerLeaderboardTools(server);
|
|
64
|
+
const mockGet = vi.fn().mockResolvedValue({ entries: [] });
|
|
65
|
+
mockedCreateApiClient.mockReturnValue({ get: mockGet });
|
|
66
|
+
const { handler } = registeredTools.get("horizon_get_leaderboard_top");
|
|
67
|
+
await handler({
|
|
68
|
+
userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
69
|
+
limit: 5,
|
|
70
|
+
leaderboardKey: "daily",
|
|
71
|
+
});
|
|
72
|
+
expect(mockGet).toHaveBeenCalledWith("/api/v1/app/leaderboards/daily/top", {
|
|
73
|
+
userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
74
|
+
limit: "5",
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=leaderboard.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leaderboard.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/leaderboard.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ export function noAdminClientResponse() {
|
|
|
19
19
|
content: [
|
|
20
20
|
{
|
|
21
21
|
type: "text",
|
|
22
|
-
text: "HORIZON_ACCOUNT_API_KEY is not configured. Admin tools require an
|
|
22
|
+
text: "HORIZON_ACCOUNT_API_KEY is not configured. Admin tools require an Account Key.",
|
|
23
23
|
},
|
|
24
24
|
],
|
|
25
25
|
isError: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_utils.js","sourceRoot":"","sources":["../../../src/tools/admin/_utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAKnD,MAAM,UAAU,cAAc;IAC5B,OAAO,2BAA2B,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EACF,
|
|
1
|
+
{"version":3,"file":"_utils.js","sourceRoot":"","sources":["../../../src/tools/admin/_utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAKnD,MAAM,UAAU,cAAc;IAC5B,OAAO,2BAA2B,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EACF,gFAAgF;aACnF;SACF;QACD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAI,IAAO;IACrC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;aACpC;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,OAAe,CAAC;IACpB,IAAI,KAAK,YAAY,eAAe,EAAE,CAAC;QACrC,OAAO,GAAG,2BAA2B,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IACtE,CAAC;SAAM,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAClC,OAAO,GAAG,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,kBAAkB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IAC9C,CAAC;IAED,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,OAAO;aACd;SACF;QACD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgBpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAqBhE"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { createAdminApiClientFromEnv } from "../admin-api-client.js";
|
|
9
9
|
import { registerAdminProjectsTools } from "./projects.js";
|
|
10
10
|
import { registerAdminRemoteConfigTools } from "./remote-config.js";
|
|
11
|
+
import { registerAdminLocalizationTools } from "./localization.js";
|
|
11
12
|
import { registerAdminNewsTools } from "./news.js";
|
|
12
13
|
import { registerAdminEmailTemplatesTools } from "./email-templates.js";
|
|
13
14
|
import { registerAdminGiftCodesTools } from "./gift-codes.js";
|
|
@@ -25,6 +26,7 @@ export function registerAllAdminTools(server) {
|
|
|
25
26
|
}
|
|
26
27
|
registerAdminProjectsTools(server);
|
|
27
28
|
registerAdminRemoteConfigTools(server);
|
|
29
|
+
registerAdminLocalizationTools(server);
|
|
28
30
|
registerAdminNewsTools(server);
|
|
29
31
|
registerAdminEmailTemplatesTools(server);
|
|
30
32
|
registerAdminGiftCodesTools(server);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAEnD,MAAM,UAAU,qBAAqB,CAAC,MAAiB;IACrD,MAAM,MAAM,GAAG,2BAA2B,EAAE,CAAC;IAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;IAED,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACvC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,gCAAgC,CAAC,MAAM,CAAC,CAAC;IACzC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAE/B,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,8BAA8B,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAEnD,MAAM,UAAU,qBAAqB,CAAC,MAAiB;IACrD,MAAM,MAAM,GAAG,2BAA2B,EAAE,CAAC;IAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;IAED,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACvC,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACvC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,gCAAgC,CAAC,MAAM,CAAC,CAAC;IACzC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAE/B,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin tools for managing localization entries.
|
|
3
|
+
*
|
|
4
|
+
* Localization is a per-API-key key/translations store the backend exposes
|
|
5
|
+
* to the runtime app. Each entry maps a localization key to one value per
|
|
6
|
+
* language (15 supported languages). These tools wrap the
|
|
7
|
+
* /api/v1/admin/localization endpoints so callers can list, create/update,
|
|
8
|
+
* delete (single, by key, and bulk) and inspect the per-key limits from the
|
|
9
|
+
* MCP surface.
|
|
10
|
+
*
|
|
11
|
+
* All tools require HORIZON_ACCOUNT_API_KEY.
|
|
12
|
+
*/
|
|
13
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
14
|
+
export declare function registerAdminLocalizationTools(server: McpServer): void;
|
|
15
|
+
//# sourceMappingURL=localization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localization.d.ts","sourceRoot":"","sources":["../../../src/tools/admin/localization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6BpE,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsOtE"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin tools for managing localization entries.
|
|
3
|
+
*
|
|
4
|
+
* Localization is a per-API-key key/translations store the backend exposes
|
|
5
|
+
* to the runtime app. Each entry maps a localization key to one value per
|
|
6
|
+
* language (15 supported languages). These tools wrap the
|
|
7
|
+
* /api/v1/admin/localization endpoints so callers can list, create/update,
|
|
8
|
+
* delete (single, by key, and bulk) and inspect the per-key limits from the
|
|
9
|
+
* MCP surface.
|
|
10
|
+
*
|
|
11
|
+
* All tools require HORIZON_ACCOUNT_API_KEY.
|
|
12
|
+
*/
|
|
13
|
+
import { z } from "zod/v4";
|
|
14
|
+
import { getAdminClient, noAdminClientResponse, jsonResponse, errorResponse, } from "./_utils.js";
|
|
15
|
+
const SUPPORTED_LANGUAGES = [
|
|
16
|
+
"en",
|
|
17
|
+
"de",
|
|
18
|
+
"es",
|
|
19
|
+
"fr",
|
|
20
|
+
"it",
|
|
21
|
+
"pt",
|
|
22
|
+
"nl",
|
|
23
|
+
"pl",
|
|
24
|
+
"ru",
|
|
25
|
+
"ja",
|
|
26
|
+
"zh",
|
|
27
|
+
"ar",
|
|
28
|
+
"ko",
|
|
29
|
+
"tr",
|
|
30
|
+
"id",
|
|
31
|
+
];
|
|
32
|
+
const SUPPORTED_LANGUAGES_HINT = SUPPORTED_LANGUAGES.join(", ");
|
|
33
|
+
export function registerAdminLocalizationTools(server) {
|
|
34
|
+
server.registerTool("horizon_admin_localization_list", {
|
|
35
|
+
title: "List Localization Entries",
|
|
36
|
+
description: "Lists localization entries for the authenticated account. Filter by projectApiKeyId to scope the result to a single project, by search to match against keys/values, and by language to scope to a single language code.",
|
|
37
|
+
inputSchema: {
|
|
38
|
+
projectApiKeyId: z
|
|
39
|
+
.string()
|
|
40
|
+
.uuid()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Optional UUID of the project API key to filter entries by. Omit to list across all projects."),
|
|
43
|
+
search: z
|
|
44
|
+
.string()
|
|
45
|
+
.optional()
|
|
46
|
+
.describe("Optional case-insensitive search on key and value"),
|
|
47
|
+
language: z
|
|
48
|
+
.string()
|
|
49
|
+
.length(2)
|
|
50
|
+
.optional()
|
|
51
|
+
.describe(`Optional ISO 639-1 language code (2 characters) to filter by. One of: ${SUPPORTED_LANGUAGES_HINT}.`),
|
|
52
|
+
page: z.number().int().min(0).default(0).describe("0-based page index"),
|
|
53
|
+
size: z
|
|
54
|
+
.number()
|
|
55
|
+
.int()
|
|
56
|
+
.min(1)
|
|
57
|
+
.max(100)
|
|
58
|
+
.default(20)
|
|
59
|
+
.describe("items per page (1-100)"),
|
|
60
|
+
},
|
|
61
|
+
}, async ({ projectApiKeyId, search, language, page, size }) => {
|
|
62
|
+
const client = getAdminClient();
|
|
63
|
+
if (!client)
|
|
64
|
+
return noAdminClientResponse();
|
|
65
|
+
try {
|
|
66
|
+
const params = {
|
|
67
|
+
page: String(page),
|
|
68
|
+
size: String(size),
|
|
69
|
+
};
|
|
70
|
+
if (projectApiKeyId !== undefined)
|
|
71
|
+
params.apiKeyId = projectApiKeyId;
|
|
72
|
+
if (search !== undefined)
|
|
73
|
+
params.search = search;
|
|
74
|
+
if (language !== undefined)
|
|
75
|
+
params.language = language;
|
|
76
|
+
const result = await client.get("/api/v1/admin/localization", params);
|
|
77
|
+
return jsonResponse(result);
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
return errorResponse(e);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
server.registerTool("horizon_admin_localization_create", {
|
|
84
|
+
title: "Create or Update Localization Entry",
|
|
85
|
+
description: "Creates a new localization entry or updates the translations if the key already exists for the given project API key. Keys must match /^[a-zA-Z0-9_.-]+$/ (1-100 chars). Provide translations as a map of language code to value.",
|
|
86
|
+
inputSchema: {
|
|
87
|
+
projectApiKeyId: z
|
|
88
|
+
.string()
|
|
89
|
+
.uuid()
|
|
90
|
+
.describe("UUID of the project API key this entry belongs to"),
|
|
91
|
+
localizationKey: z
|
|
92
|
+
.string()
|
|
93
|
+
.min(1)
|
|
94
|
+
.max(100)
|
|
95
|
+
.regex(/^[a-zA-Z0-9_.-]+$/)
|
|
96
|
+
.describe("Localization key (1-100 chars, alphanumeric + _ . -). Dot-notation recommended."),
|
|
97
|
+
translations: z
|
|
98
|
+
// Backend enforces the real per-tier cap (ADMIN allows up to 2000 chars);
|
|
99
|
+
// keep a generous client-side guard so valid ADMIN writes are not blocked.
|
|
100
|
+
.record(z.string(), z.string().max(2000))
|
|
101
|
+
.refine((obj) => {
|
|
102
|
+
const keys = Object.keys(obj);
|
|
103
|
+
return (keys.length > 0 &&
|
|
104
|
+
keys.every((k) => SUPPORTED_LANGUAGES.includes(k)));
|
|
105
|
+
}, {
|
|
106
|
+
message: `translations must contain at least one entry, and every key must be a supported language code (${SUPPORTED_LANGUAGES_HINT})`,
|
|
107
|
+
})
|
|
108
|
+
.describe(`Map of language code to translated value (max chars per value is tier-enforced server-side; ADMIN allows up to 2000). Supported keys: ${SUPPORTED_LANGUAGES_HINT}.`),
|
|
109
|
+
},
|
|
110
|
+
}, async ({ projectApiKeyId, localizationKey, translations }) => {
|
|
111
|
+
const client = getAdminClient();
|
|
112
|
+
if (!client)
|
|
113
|
+
return noAdminClientResponse();
|
|
114
|
+
try {
|
|
115
|
+
const body = {
|
|
116
|
+
apiKeyId: projectApiKeyId,
|
|
117
|
+
localizationKey,
|
|
118
|
+
translations,
|
|
119
|
+
};
|
|
120
|
+
const result = await client.post("/api/v1/admin/localization", body);
|
|
121
|
+
return jsonResponse(result);
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
return errorResponse(e);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
server.registerTool("horizon_admin_localization_delete", {
|
|
128
|
+
title: "Delete Localization Entry",
|
|
129
|
+
description: "Soft-deletes a localization entry by its UUID. After deletion the entry is no longer returned by the runtime app API.",
|
|
130
|
+
inputSchema: {
|
|
131
|
+
id: z
|
|
132
|
+
.string()
|
|
133
|
+
.uuid()
|
|
134
|
+
.describe("UUID of the localization entry to delete"),
|
|
135
|
+
},
|
|
136
|
+
}, async ({ id }) => {
|
|
137
|
+
const client = getAdminClient();
|
|
138
|
+
if (!client)
|
|
139
|
+
return noAdminClientResponse();
|
|
140
|
+
try {
|
|
141
|
+
const result = await client.delete(`/api/v1/admin/localization/${id}`);
|
|
142
|
+
return jsonResponse(result);
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
return errorResponse(e);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
server.registerTool("horizon_admin_localization_deleteByKey", {
|
|
149
|
+
title: "Delete Localization Entry by Key",
|
|
150
|
+
description: "Soft-deletes a localization entry by its localizationKey for a specific project API key. Useful when the entry UUID is not known.",
|
|
151
|
+
inputSchema: {
|
|
152
|
+
projectApiKeyId: z
|
|
153
|
+
.string()
|
|
154
|
+
.uuid()
|
|
155
|
+
.describe("UUID of the project API key the entry belongs to"),
|
|
156
|
+
localizationKey: z
|
|
157
|
+
.string()
|
|
158
|
+
.min(1)
|
|
159
|
+
.max(100)
|
|
160
|
+
.describe("Localization key to delete"),
|
|
161
|
+
},
|
|
162
|
+
}, async ({ projectApiKeyId, localizationKey }) => {
|
|
163
|
+
const client = getAdminClient();
|
|
164
|
+
if (!client)
|
|
165
|
+
return noAdminClientResponse();
|
|
166
|
+
try {
|
|
167
|
+
const path = `/api/v1/admin/localization/api-key/${projectApiKeyId}/key/${encodeURIComponent(localizationKey)}`;
|
|
168
|
+
const result = await client.delete(path);
|
|
169
|
+
return jsonResponse(result);
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
return errorResponse(e);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
server.registerTool("horizon_admin_localization_bulkDelete", {
|
|
176
|
+
title: "Bulk Delete Localization Entries",
|
|
177
|
+
description: "Deletes up to 10000 localization entries in a single request. Each entry is processed independently; the response reports per-entry success/failure.",
|
|
178
|
+
inputSchema: {
|
|
179
|
+
ids: z
|
|
180
|
+
.array(z.string().uuid())
|
|
181
|
+
.min(1)
|
|
182
|
+
.max(10000)
|
|
183
|
+
.describe("List of entry UUIDs to delete (1-10000)"),
|
|
184
|
+
},
|
|
185
|
+
}, async ({ ids }) => {
|
|
186
|
+
const client = getAdminClient();
|
|
187
|
+
if (!client)
|
|
188
|
+
return noAdminClientResponse();
|
|
189
|
+
try {
|
|
190
|
+
const result = await client.post("/api/v1/admin/localization/bulk-delete", { ids });
|
|
191
|
+
return jsonResponse(result);
|
|
192
|
+
}
|
|
193
|
+
catch (e) {
|
|
194
|
+
return errorResponse(e);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
server.registerTool("horizon_admin_localization_getLimits", {
|
|
198
|
+
title: "Get Localization Limits",
|
|
199
|
+
description: "Returns the localization key usage and limits for a specific project API key: used (current key count), maxKeys, maxCharsPerValue, and role.",
|
|
200
|
+
inputSchema: {
|
|
201
|
+
projectApiKeyId: z
|
|
202
|
+
.string()
|
|
203
|
+
.uuid()
|
|
204
|
+
.describe("UUID of the project API key to inspect"),
|
|
205
|
+
},
|
|
206
|
+
}, async ({ projectApiKeyId }) => {
|
|
207
|
+
const client = getAdminClient();
|
|
208
|
+
if (!client)
|
|
209
|
+
return noAdminClientResponse();
|
|
210
|
+
try {
|
|
211
|
+
const result = await client.get(`/api/v1/admin/localization/api-key/${projectApiKeyId}/limits`);
|
|
212
|
+
return jsonResponse(result);
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
return errorResponse(e);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=localization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localization.js","sourceRoot":"","sources":["../../../src/tools/admin/localization.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Admin API client factory.
|
|
3
3
|
*
|
|
4
|
-
* Uses HORIZON_ACCOUNT_API_KEY (
|
|
4
|
+
* Uses HORIZON_ACCOUNT_API_KEY (Account Key) and sends it as
|
|
5
5
|
* X-Account-API-Key so the backend routes the request to the
|
|
6
6
|
* AccountApiKeyAuthenticationFilter.
|
|
7
7
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Admin API client factory.
|
|
3
3
|
*
|
|
4
|
-
* Uses HORIZON_ACCOUNT_API_KEY (
|
|
4
|
+
* Uses HORIZON_ACCOUNT_API_KEY (Account Key) and sends it as
|
|
5
5
|
* X-Account-API-Key so the backend routes the request to the
|
|
6
6
|
* AccountApiKeyAuthenticationFilter.
|
|
7
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAepE;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoBxD"}
|
package/dist/tools/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { registerAuthTools } from "./auth.js";
|
|
|
3
3
|
import { registerLeaderboardTools } from "./leaderboard.js";
|
|
4
4
|
import { registerCloudSaveTools } from "./cloud-save.js";
|
|
5
5
|
import { registerRemoteConfigTools } from "./remote-config.js";
|
|
6
|
+
import { registerLocalizationTools } from "./localization.js";
|
|
6
7
|
import { registerNewsTools } from "./news.js";
|
|
7
8
|
import { registerGiftCodeTools } from "./gift-codes.js";
|
|
8
9
|
import { registerFeedbackTools } from "./feedback.js";
|
|
@@ -19,6 +20,7 @@ export function registerAllTools(server) {
|
|
|
19
20
|
registerLeaderboardTools(server);
|
|
20
21
|
registerCloudSaveTools(server);
|
|
21
22
|
registerRemoteConfigTools(server);
|
|
23
|
+
registerLocalizationTools(server);
|
|
22
24
|
registerNewsTools(server);
|
|
23
25
|
registerGiftCodeTools(server);
|
|
24
26
|
registerFeedbackTools(server);
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACjC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAElC,MAAM,YAAY,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CACX,iEAAiE,CAClE,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACjC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAElC,MAAM,YAAY,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CACX,iEAAiE,CAClE,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leaderboard.d.ts","sourceRoot":"","sources":["../../src/tools/leaderboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqCpE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"leaderboard.d.ts","sourceRoot":"","sources":["../../src/tools/leaderboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqCpE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyJhE"}
|
|
@@ -28,6 +28,23 @@ function aroundPath(leaderboardKey) {
|
|
|
28
28
|
: "/api/v1/app/leaderboard/around";
|
|
29
29
|
}
|
|
30
30
|
export function registerLeaderboardTools(server) {
|
|
31
|
+
// --- List leaderboard boards ---
|
|
32
|
+
server.registerTool("horizon_list_leaderboards", {
|
|
33
|
+
title: "List Leaderboard Boards",
|
|
34
|
+
description: "Lists the available horizOn leaderboard boards for the configured app API key, including each board key for multi-board calls.",
|
|
35
|
+
inputSchema: {},
|
|
36
|
+
}, async () => {
|
|
37
|
+
const client = createApiClientFromEnv();
|
|
38
|
+
if (!client)
|
|
39
|
+
return noApiKeyResponse();
|
|
40
|
+
try {
|
|
41
|
+
const result = await client.get("/api/v1/app/leaderboards");
|
|
42
|
+
return jsonResponse(result);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
return errorResponse(error);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
31
48
|
// --- Submit score ---
|
|
32
49
|
server.registerTool("horizon_submit_score", {
|
|
33
50
|
title: "Submit Score",
|
|
@@ -49,7 +66,10 @@ export function registerLeaderboardTools(server) {
|
|
|
49
66
|
const path = leaderboardKey
|
|
50
67
|
? `/api/v1/app/leaderboards/${encodeURIComponent(leaderboardKey)}/submit`
|
|
51
68
|
: "/api/v1/app/leaderboard/submit";
|
|
52
|
-
const
|
|
69
|
+
const body = leaderboardKey
|
|
70
|
+
? { userId, score, leaderboardKey }
|
|
71
|
+
: { userId, score };
|
|
72
|
+
const result = await client.post(path, body);
|
|
53
73
|
return jsonResponse(result);
|
|
54
74
|
}
|
|
55
75
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leaderboard.js","sourceRoot":"","sources":["../../src/tools/leaderboard.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAElF;;;GAGG;AACH,MAAM,oBAAoB,GAAG,CAAC;KAC3B,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CAAC,EAAE,CAAC;KACP,KAAK,CAAC,eAAe,EAAE,oCAAoC,CAAC;KAC5D,QAAQ,EAAE;KACV,QAAQ,CACP,wFAAwF,CACzF,CAAC;AAEJ,SAAS,OAAO,CAAC,cAAuB;IACtC,OAAO,cAAc;QACnB,CAAC,CAAC,4BAA4B,kBAAkB,CAAC,cAAc,CAAC,MAAM;QACtE,CAAC,CAAC,6BAA6B,CAAC;AACpC,CAAC;AAED,SAAS,QAAQ,CAAC,cAAuB;IACvC,OAAO,cAAc;QACnB,CAAC,CAAC,4BAA4B,kBAAkB,CAAC,cAAc,CAAC,OAAO;QACvE,CAAC,CAAC,8BAA8B,CAAC;AACrC,CAAC;AAED,SAAS,UAAU,CAAC,cAAuB;IACzC,OAAO,cAAc;QACnB,CAAC,CAAC,4BAA4B,kBAAkB,CAAC,cAAc,CAAC,SAAS;QACzE,CAAC,CAAC,gCAAgC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,uBAAuB;IACvB,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,2IAA2I;QAC7I,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YACpD,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CAAC,wCAAwC,CAAC;YACrD,cAAc,EAAE,oBAAoB;SACrC;KACF,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE;QAC1C,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC;QACxC,IAAI,CAAC,MAAM;YAAE,OAAO,gBAAgB,EAAE,CAAC;QAEvC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,cAAc;gBACzB,CAAC,CAAC,4BAA4B,kBAAkB,CAAC,cAAc,CAAC,SAAS;gBACzE,CAAC,CAAC,gCAAgC,CAAC;YACrC,MAAM,
|
|
1
|
+
{"version":3,"file":"leaderboard.js","sourceRoot":"","sources":["../../src/tools/leaderboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localization.d.ts","sourceRoot":"","sources":["../../src/tools/localization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAqEjE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { createApiClientFromEnv } from "./api-client.js";
|
|
3
|
+
import { noApiKeyResponse, errorResponse, jsonResponse } from "./tool-helpers.js";
|
|
4
|
+
const SUPPORTED_LANGUAGES_HINT = "One of: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id.";
|
|
5
|
+
export function registerLocalizationTools(server) {
|
|
6
|
+
// --- Get single localization ---
|
|
7
|
+
server.registerTool("horizon_get_localization", {
|
|
8
|
+
title: "Get Localization",
|
|
9
|
+
description: "Gets a single localized string value by key from horizOn, optionally for a specific language.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
key: z.string().max(100).describe("Localization key (max 100 characters)"),
|
|
12
|
+
lang: z
|
|
13
|
+
.string()
|
|
14
|
+
.length(2)
|
|
15
|
+
.optional()
|
|
16
|
+
.describe(`ISO 639-1 language code (2 characters). ${SUPPORTED_LANGUAGES_HINT}`),
|
|
17
|
+
},
|
|
18
|
+
}, async ({ key, lang }) => {
|
|
19
|
+
const client = createApiClientFromEnv();
|
|
20
|
+
if (!client)
|
|
21
|
+
return noApiKeyResponse();
|
|
22
|
+
try {
|
|
23
|
+
const encodedKey = encodeURIComponent(key);
|
|
24
|
+
const params = lang ? { lang } : undefined;
|
|
25
|
+
const result = await client.get(`/api/v1/app/localization/${encodedKey}`, params);
|
|
26
|
+
return jsonResponse(result);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return errorResponse(error);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
// --- Get all localizations ---
|
|
33
|
+
server.registerTool("horizon_get_all_localizations", {
|
|
34
|
+
title: "Get All Localizations",
|
|
35
|
+
description: "Gets all localized strings from horizOn, optionally for a specific language.",
|
|
36
|
+
inputSchema: {
|
|
37
|
+
lang: z
|
|
38
|
+
.string()
|
|
39
|
+
.length(2)
|
|
40
|
+
.optional()
|
|
41
|
+
.describe(`ISO 639-1 language code (2 characters). ${SUPPORTED_LANGUAGES_HINT}`),
|
|
42
|
+
},
|
|
43
|
+
}, async ({ lang }) => {
|
|
44
|
+
const client = createApiClientFromEnv();
|
|
45
|
+
if (!client)
|
|
46
|
+
return noApiKeyResponse();
|
|
47
|
+
try {
|
|
48
|
+
const params = lang ? { lang } : undefined;
|
|
49
|
+
const result = await client.get("/api/v1/app/localization/all", params);
|
|
50
|
+
return jsonResponse(result);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return errorResponse(error);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
// --- Get available languages ---
|
|
57
|
+
server.registerTool("horizon_get_localization_languages", {
|
|
58
|
+
title: "Get Localization Languages",
|
|
59
|
+
description: "Gets the list of languages that have localizations available for the app.",
|
|
60
|
+
}, async () => {
|
|
61
|
+
const client = createApiClientFromEnv();
|
|
62
|
+
if (!client)
|
|
63
|
+
return noApiKeyResponse();
|
|
64
|
+
try {
|
|
65
|
+
const result = await client.get("/api/v1/app/localization/languages");
|
|
66
|
+
return jsonResponse(result);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return errorResponse(error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=localization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localization.js","sourceRoot":"","sources":["../../src/tools/localization.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "horizon-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "MCP server for horizOn Backend-as-a-Service — documentation, live API tools, and workflow prompts for Godot, Unity, and Unreal Engine integration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -188,6 +188,37 @@ Reset password with a reset token.
|
|
|
188
188
|
|
|
189
189
|
## Leaderboard
|
|
190
190
|
|
|
191
|
+
### GET /api/v1/app/leaderboards
|
|
192
|
+
|
|
193
|
+
List the leaderboard boards configured for the app API key.
|
|
194
|
+
|
|
195
|
+
**Response (200):**
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"boards": [
|
|
199
|
+
{
|
|
200
|
+
"key": "weekly",
|
|
201
|
+
"name": "Weekly",
|
|
202
|
+
"sortOrder": "DESC",
|
|
203
|
+
"isActive": true,
|
|
204
|
+
"scoreCount": 10
|
|
205
|
+
}
|
|
206
|
+
],
|
|
207
|
+
"totalElements": 1
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Use the returned `key` with the V2 board endpoints:
|
|
212
|
+
|
|
213
|
+
- `POST /api/v1/app/leaderboards/{boardKey}/submit`
|
|
214
|
+
- `GET /api/v1/app/leaderboards/{boardKey}/top?userId={userId}&limit={limit}`
|
|
215
|
+
- `GET /api/v1/app/leaderboards/{boardKey}/rank?userId={userId}`
|
|
216
|
+
- `GET /api/v1/app/leaderboards/{boardKey}/around?userId={userId}&range={range}`
|
|
217
|
+
|
|
218
|
+
Omit `boardKey` and use the legacy singular endpoints below for the default board.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
191
222
|
### POST /api/v1/app/leaderboard/submit
|
|
192
223
|
|
|
193
224
|
Submit a score (only updates if higher than previous best).
|
|
@@ -196,7 +227,8 @@ Submit a score (only updates if higher than previous best).
|
|
|
196
227
|
```json
|
|
197
228
|
{
|
|
198
229
|
"userId": "string",
|
|
199
|
-
"score": "number (positive integer)"
|
|
230
|
+
"score": "number (positive integer)",
|
|
231
|
+
"leaderboardKey": "string (optional)"
|
|
200
232
|
}
|
|
201
233
|
```
|
|
202
234
|
|
|
@@ -6,6 +6,42 @@ horizOn leaderboards provide global rankings for your app. Scores are submitted
|
|
|
6
6
|
|
|
7
7
|
## Endpoints
|
|
8
8
|
|
|
9
|
+
The legacy singular endpoints target the default board. For multiple boards, first list available boards and pass the returned board `key` to the V2 endpoints.
|
|
10
|
+
|
|
11
|
+
### List Boards
|
|
12
|
+
|
|
13
|
+
**`GET /api/v1/app/leaderboards`**
|
|
14
|
+
|
|
15
|
+
Returns the leaderboard boards configured for the app API key.
|
|
16
|
+
|
|
17
|
+
**Response (200):**
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"boards": [
|
|
22
|
+
{
|
|
23
|
+
"key": "weekly",
|
|
24
|
+
"name": "Weekly",
|
|
25
|
+
"sortOrder": "DESC",
|
|
26
|
+
"isActive": true,
|
|
27
|
+
"scoreCount": 10
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"totalElements": 1
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Multi-Board Endpoints
|
|
35
|
+
|
|
36
|
+
Use these endpoints with a board key from `GET /api/v1/app/leaderboards`:
|
|
37
|
+
|
|
38
|
+
| Operation | Endpoint |
|
|
39
|
+
|-----------|----------|
|
|
40
|
+
| Submit score | `POST /api/v1/app/leaderboards/{boardKey}/submit` |
|
|
41
|
+
| Top entries | `GET /api/v1/app/leaderboards/{boardKey}/top?userId={userId}&limit={limit}` |
|
|
42
|
+
| User rank | `GET /api/v1/app/leaderboards/{boardKey}/rank?userId={userId}` |
|
|
43
|
+
| Around user | `GET /api/v1/app/leaderboards/{boardKey}/around?userId={userId}&range={range}` |
|
|
44
|
+
|
|
9
45
|
### Submit Score
|
|
10
46
|
|
|
11
47
|
**`POST /api/v1/app/leaderboard/submit`**
|
|
@@ -18,6 +54,7 @@ Submits a score for the authenticated user. Only updates if the score is higher
|
|
|
18
54
|
|-------|------|----------|-------------|
|
|
19
55
|
| `userId` | string | Yes | The user's ID |
|
|
20
56
|
| `score` | number | Yes | Score value (positive integer) |
|
|
57
|
+
| `leaderboardKey` | string | No | Optional named board key for V2 calls |
|
|
21
58
|
|
|
22
59
|
**Response (200):**
|
|
23
60
|
|
|
@@ -114,6 +151,9 @@ Returns entries around the user's position (players ranked near them).
|
|
|
114
151
|
# Submit a score (only updates if higher than previous best)
|
|
115
152
|
await Horizon.leaderboard.submitScore(1000)
|
|
116
153
|
|
|
154
|
+
# Submit to a named board
|
|
155
|
+
await Horizon.leaderboard.submitScore(1000, "weekly")
|
|
156
|
+
|
|
117
157
|
# Get top 10 players
|
|
118
158
|
var top: Array[HorizonLeaderboardEntry] = await Horizon.leaderboard.getTop(10)
|
|
119
159
|
for entry in top:
|
|
@@ -126,6 +166,9 @@ print("My rank: #%d (Score: %d)" % [myRank.position, myRank.score])
|
|
|
126
166
|
# Get entries around the user's position
|
|
127
167
|
var around: Array[HorizonLeaderboardEntry] = await Horizon.leaderboard.getAround(5)
|
|
128
168
|
|
|
169
|
+
# List boards
|
|
170
|
+
var boards: Array[Dictionary] = await Horizon.leaderboard.listBoards()
|
|
171
|
+
|
|
129
172
|
# Use caching (enabled by default)
|
|
130
173
|
var cached_top = await Horizon.leaderboard.getTop(10, true) # uses cache
|
|
131
174
|
var fresh_top = await Horizon.leaderboard.getTop(10, false) # forces refresh
|
|
@@ -146,6 +189,9 @@ using PM.horizOn.Cloud.Manager;
|
|
|
146
189
|
// Submit score
|
|
147
190
|
await LeaderboardManager.Instance.SubmitScore(12500);
|
|
148
191
|
|
|
192
|
+
// Submit to a named board
|
|
193
|
+
await LeaderboardManager.Instance.SubmitScore(12500, boardKey: "weekly");
|
|
194
|
+
|
|
149
195
|
// Get top 10 players
|
|
150
196
|
var top = await LeaderboardManager.Instance.GetTop(10);
|
|
151
197
|
foreach (var entry in top)
|
|
@@ -160,6 +206,9 @@ Debug.Log($"My rank: #{rank.position} (Score: {rank.score})");
|
|
|
160
206
|
// Get entries around user
|
|
161
207
|
var around = await LeaderboardManager.Instance.GetAround(5);
|
|
162
208
|
|
|
209
|
+
// List boards
|
|
210
|
+
var boards = await LeaderboardManager.Instance.ListBoards();
|
|
211
|
+
|
|
163
212
|
// Clear cache
|
|
164
213
|
LeaderboardManager.Instance.ClearCache();
|
|
165
214
|
```
|
|
@@ -173,6 +222,12 @@ curl -X POST https://horizon.pm/api/v1/app/leaderboard/submit \
|
|
|
173
222
|
-H "Content-Type: application/json" \
|
|
174
223
|
-d '{"userId": "user123", "score": 12500}'
|
|
175
224
|
|
|
225
|
+
# Submit to a named board
|
|
226
|
+
curl -X POST https://horizon.pm/api/v1/app/leaderboards/weekly/submit \
|
|
227
|
+
-H "X-API-Key: YOUR_API_KEY" \
|
|
228
|
+
-H "Content-Type: application/json" \
|
|
229
|
+
-d '{"userId": "user123", "score": 12500, "leaderboardKey": "weekly"}'
|
|
230
|
+
|
|
176
231
|
# Get top 10
|
|
177
232
|
curl "https://horizon.pm/api/v1/app/leaderboard/top?userId=user123&limit=10" \
|
|
178
233
|
-H "X-API-Key: YOUR_API_KEY"
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Localization
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Localization lets you store translated strings on the server that your app can fetch at runtime. Each localization key holds one value per language, so you can ship copy in many languages without an app update. This is useful for:
|
|
6
|
+
|
|
7
|
+
- **UI text** — Buttons, labels, menus, and dialogs in the player's language
|
|
8
|
+
- **In-game content** — Item names, descriptions, quest text
|
|
9
|
+
- **Live updates** — Fix typos or change wording without a new build
|
|
10
|
+
- **Market expansion** — Add a new language without touching the client
|
|
11
|
+
|
|
12
|
+
horizOn supports **15 languages**: `en`, `de`, `es`, `fr`, `it`, `pt`, `nl`, `pl`, `ru`, `ja`, `zh`, `ar`, `ko`, `tr`, `id`.
|
|
13
|
+
|
|
14
|
+
Localization values are set in the horizOn Dashboard and are read-only from the app side. When no `lang` is given, the backend resolves the value for its default language.
|
|
15
|
+
|
|
16
|
+
## Endpoints
|
|
17
|
+
|
|
18
|
+
### Get Single Localization
|
|
19
|
+
|
|
20
|
+
**`GET /api/v1/app/localization/{localizationKey}?lang=xx`**
|
|
21
|
+
|
|
22
|
+
Retrieves a single localized value by its key. The optional `lang` query parameter selects the language (ISO 639-1, 2 characters).
|
|
23
|
+
|
|
24
|
+
**Path Parameters:**
|
|
25
|
+
|
|
26
|
+
| Param | Type | Required | Description |
|
|
27
|
+
|-------|------|----------|-------------|
|
|
28
|
+
| `localizationKey` | string | Yes | The localization key |
|
|
29
|
+
|
|
30
|
+
**Query Parameters:**
|
|
31
|
+
|
|
32
|
+
| Param | Type | Required | Description |
|
|
33
|
+
|-------|------|----------|-------------|
|
|
34
|
+
| `lang` | string | No | ISO 639-1 language code (e.g. `de`). Defaults to the configured default language. |
|
|
35
|
+
|
|
36
|
+
**Response (200):**
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"localizationKey": "ui.play_button",
|
|
41
|
+
"value": "Spielen",
|
|
42
|
+
"language": "de",
|
|
43
|
+
"found": true
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
If the key does not exist:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"localizationKey": "unknown_key",
|
|
52
|
+
"value": null,
|
|
53
|
+
"language": "de",
|
|
54
|
+
"found": false
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### Get All Localizations
|
|
61
|
+
|
|
62
|
+
**`GET /api/v1/app/localization/all?lang=xx`**
|
|
63
|
+
|
|
64
|
+
Retrieves all localized values for a single language as a key-value map.
|
|
65
|
+
|
|
66
|
+
**Query Parameters:**
|
|
67
|
+
|
|
68
|
+
| Param | Type | Required | Description |
|
|
69
|
+
|-------|------|----------|-------------|
|
|
70
|
+
| `lang` | string | No | ISO 639-1 language code (e.g. `de`). Defaults to the configured default language. |
|
|
71
|
+
|
|
72
|
+
**Response (200):**
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"translations": {
|
|
77
|
+
"ui.play_button": "Play",
|
|
78
|
+
"ui.settings": "Settings",
|
|
79
|
+
"ui.quit": "Quit"
|
|
80
|
+
},
|
|
81
|
+
"language": "en",
|
|
82
|
+
"total": 3
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### Get Available Languages
|
|
89
|
+
|
|
90
|
+
**`GET /api/v1/app/localization/languages`**
|
|
91
|
+
|
|
92
|
+
Returns the list of languages that have at least one localization available for the app.
|
|
93
|
+
|
|
94
|
+
**Response (200):**
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"languages": ["en", "de", "es", "fr"],
|
|
99
|
+
"total": 4
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Code Examples
|
|
104
|
+
|
|
105
|
+
### Godot (GDScript)
|
|
106
|
+
|
|
107
|
+
```gdscript
|
|
108
|
+
# Set the active language (defaults to the device language)
|
|
109
|
+
Horizon.localization.setLanguage("de")
|
|
110
|
+
|
|
111
|
+
# Get a single localized string in the active language
|
|
112
|
+
var label: String = await Horizon.localization.getLocalization("ui.play_button")
|
|
113
|
+
|
|
114
|
+
# Get a string for a specific language
|
|
115
|
+
var en_label: String = await Horizon.localization.getLocalization("ui.play_button", "en")
|
|
116
|
+
|
|
117
|
+
# Get all localizations at once (recommended at startup)
|
|
118
|
+
var all: Dictionary = await Horizon.localization.getAllLocalizations()
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Unity (C#)
|
|
122
|
+
|
|
123
|
+
```csharp
|
|
124
|
+
using PM.horizOn.Cloud.Manager;
|
|
125
|
+
|
|
126
|
+
// Set the active language (en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id)
|
|
127
|
+
LocalizationManager.Instance.SetLanguage("de");
|
|
128
|
+
|
|
129
|
+
// Get a single localized string in the active language
|
|
130
|
+
string label = await LocalizationManager.Instance.GetLocalization("ui.play_button");
|
|
131
|
+
|
|
132
|
+
// Get a string for a specific language
|
|
133
|
+
string enLabel = await LocalizationManager.Instance.GetLocalization("ui.play_button", "en");
|
|
134
|
+
|
|
135
|
+
// Get all localizations at once (recommended at startup)
|
|
136
|
+
var translations = await LocalizationManager.Instance.GetAllLocalizations();
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### REST (cURL)
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Get single localization (German)
|
|
143
|
+
curl "https://horizon.pm/api/v1/app/localization/ui.play_button?lang=de" \
|
|
144
|
+
-H "X-API-Key: YOUR_API_KEY"
|
|
145
|
+
|
|
146
|
+
# Get all localizations for a language
|
|
147
|
+
curl "https://horizon.pm/api/v1/app/localization/all?lang=de" \
|
|
148
|
+
-H "X-API-Key: YOUR_API_KEY"
|
|
149
|
+
|
|
150
|
+
# List available languages
|
|
151
|
+
curl "https://horizon.pm/api/v1/app/localization/languages" \
|
|
152
|
+
-H "X-API-Key: YOUR_API_KEY"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Best Practices
|
|
156
|
+
|
|
157
|
+
- **Fetch all localizations at startup** — Use `getAllLocalizations()` once per language on app launch and rely on the cache.
|
|
158
|
+
- **Set the language once** — Resolve the player's language at startup (device locale or saved preference) and call `setLanguage()` before loading UI.
|
|
159
|
+
- **Provide a fallback language** — Always have `en` populated; fall back to it when a key is missing in the selected language.
|
|
160
|
+
- **Use dot-notation keys** — Group keys like `ui.play_button` or `quest.intro.title` for maintainability.
|
|
161
|
+
- **Avoid frequent polling** — Translations rarely change during a session; refetch only when the language changes.
|
|
162
|
+
|
|
163
|
+
## Common Errors
|
|
164
|
+
|
|
165
|
+
| Status | Cause | Solution |
|
|
166
|
+
|--------|-------|----------|
|
|
167
|
+
| 400 | Unsupported language code | Use one of the 15 supported codes (en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id) |
|
|
168
|
+
| 401 | Invalid API key | Check `X-API-Key` header |
|
|
169
|
+
| 429 | Rate limit exceeded | Cache localizations, fetch once at startup |
|
|
@@ -127,6 +127,22 @@ var maintenance: bool = await Horizon.remoteConfig.getBool("maintenance_mode", f
|
|
|
127
127
|
var all_configs: Dictionary = await Horizon.remoteConfig.getAllConfigs()
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
### Localization
|
|
131
|
+
|
|
132
|
+
```gdscript
|
|
133
|
+
# Set the active language (en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id)
|
|
134
|
+
Horizon.localization.setLanguage("de")
|
|
135
|
+
|
|
136
|
+
# Get a single localized string in the active language
|
|
137
|
+
var label: String = await Horizon.localization.getLocalization("ui.play_button")
|
|
138
|
+
|
|
139
|
+
# Get a string for a specific language
|
|
140
|
+
var en_label: String = await Horizon.localization.getLocalization("ui.play_button", "en")
|
|
141
|
+
|
|
142
|
+
# Get all localizations at once (recommended at startup)
|
|
143
|
+
var all_translations: Dictionary = await Horizon.localization.getAllLocalizations()
|
|
144
|
+
```
|
|
145
|
+
|
|
130
146
|
### News
|
|
131
147
|
|
|
132
148
|
```gdscript
|
|
@@ -153,6 +153,24 @@ string version = await RemoteConfigManager.Instance.GetString("game_version", "1
|
|
|
153
153
|
var configs = await RemoteConfigManager.Instance.GetAllConfigs();
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
+
### Localization
|
|
157
|
+
|
|
158
|
+
```csharp
|
|
159
|
+
using PM.horizOn.Cloud.Manager;
|
|
160
|
+
|
|
161
|
+
// Set the active language (en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id)
|
|
162
|
+
LocalizationManager.Instance.SetLanguage("de");
|
|
163
|
+
|
|
164
|
+
// Get a single localized string in the active language
|
|
165
|
+
string label = await LocalizationManager.Instance.GetLocalization("ui.play_button");
|
|
166
|
+
|
|
167
|
+
// Get a string for a specific language
|
|
168
|
+
string enLabel = await LocalizationManager.Instance.GetLocalization("ui.play_button", "en");
|
|
169
|
+
|
|
170
|
+
// Get all localizations at once (recommended at startup)
|
|
171
|
+
var translations = await LocalizationManager.Instance.GetAllLocalizations();
|
|
172
|
+
```
|
|
173
|
+
|
|
156
174
|
### News
|
|
157
175
|
|
|
158
176
|
```csharp
|
|
@@ -325,6 +325,45 @@ void GetAllRemoteConfigs()
|
|
|
325
325
|
}
|
|
326
326
|
```
|
|
327
327
|
|
|
328
|
+
### Get Localizations
|
|
329
|
+
|
|
330
|
+
```cpp
|
|
331
|
+
// SetLanguage simply means appending ?lang=xx to the request (en, de, es,
|
|
332
|
+
// fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id).
|
|
333
|
+
void GetLocalization(const FString& Key, const FString& Lang)
|
|
334
|
+
{
|
|
335
|
+
FHorizonAPI::Get(FString::Printf(TEXT("/api/v1/app/localization/%s?lang=%s"), *Key, *Lang),
|
|
336
|
+
[](bool bSuccess, TSharedPtr<FJsonObject> Response)
|
|
337
|
+
{
|
|
338
|
+
if (bSuccess && Response.IsValid() && Response->GetBoolField(TEXT("found")))
|
|
339
|
+
{
|
|
340
|
+
UE_LOG(LogTemp, Log, TEXT("Localization: %s"),
|
|
341
|
+
*Response->GetStringField(TEXT("value")));
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
void GetAllLocalizations(const FString& Lang)
|
|
347
|
+
{
|
|
348
|
+
FHorizonAPI::Get(FString::Printf(TEXT("/api/v1/app/localization/all?lang=%s"), *Lang),
|
|
349
|
+
[](bool bSuccess, TSharedPtr<FJsonObject> Response)
|
|
350
|
+
{
|
|
351
|
+
if (bSuccess && Response.IsValid())
|
|
352
|
+
{
|
|
353
|
+
const TSharedPtr<FJsonObject>* Translations;
|
|
354
|
+
if (Response->TryGetObjectField(TEXT("translations"), Translations))
|
|
355
|
+
{
|
|
356
|
+
for (const auto& Pair : (*Translations)->Values)
|
|
357
|
+
{
|
|
358
|
+
UE_LOG(LogTemp, Log, TEXT("Localization: %s = %s"),
|
|
359
|
+
*Pair.Key, *Pair.Value->AsString());
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
328
367
|
## REST Examples (cURL)
|
|
329
368
|
|
|
330
369
|
These cURL examples show the raw HTTP requests. Translate them to your preferred Unreal HTTP method.
|
|
@@ -346,6 +385,10 @@ curl -X POST https://horizon.pm/api/v1/app/leaderboard/submit \
|
|
|
346
385
|
curl "https://horizon.pm/api/v1/app/remote-config/all" \
|
|
347
386
|
-H "X-API-Key: YOUR_API_KEY"
|
|
348
387
|
|
|
388
|
+
# Get all localizations (German)
|
|
389
|
+
curl "https://horizon.pm/api/v1/app/localization/all?lang=de" \
|
|
390
|
+
-H "X-API-Key: YOUR_API_KEY"
|
|
391
|
+
|
|
349
392
|
# Save cloud data
|
|
350
393
|
curl -X POST https://horizon.pm/api/v1/app/cloud-save/save \
|
|
351
394
|
-H "X-API-Key: YOUR_API_KEY" \
|