gamealgo-cli 0.4.3 → 0.4.4
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 +3 -0
- package/dist/client.js +3 -0
- package/dist/commands/dynamic-config.js +6 -0
- package/dist/commands/quota.js +16 -0
- package/dist/main.js +5 -0
- package/package.json +1 -1
- package/skills/gamealgo/SKILL.md +9 -3
package/README.md
CHANGED
|
@@ -18,10 +18,13 @@ Run login from the game repository that should own the credentials:
|
|
|
18
18
|
```bash
|
|
19
19
|
gamealgo login --host <admin-url> --admin-key <ga_admin_key>
|
|
20
20
|
gamealgo whoami
|
|
21
|
+
gamealgo quota --json
|
|
21
22
|
```
|
|
22
23
|
|
|
23
24
|
The login is stored in the current project's `.gamealgo/cli.json`, which is automatically ignored by Git. Authenticated commands require this project-scoped login and verify its `gameId` against the Server before continuing, preventing credentials from another game from being reused accidentally.
|
|
24
25
|
|
|
26
|
+
`gamealgo quota --json` returns the current effective plan, the per-user daily ordinary-event limit, UTC reset time, detail-query and retention windows, exempt revenue events, and today's actual quota-filtered count. Check it before adding or increasing telemetry.
|
|
27
|
+
|
|
25
28
|
## Current help and documentation
|
|
26
29
|
|
|
27
30
|
```bash
|
package/dist/client.js
CHANGED
|
@@ -201,6 +201,9 @@ export class GameAlgoAdminClient {
|
|
|
201
201
|
async countEvents(body, options = {}) {
|
|
202
202
|
return await this.post(`/admin/v1/games/${encodeURIComponent(await this.gameId())}/events/count`, body, options);
|
|
203
203
|
}
|
|
204
|
+
async getGameQuota() {
|
|
205
|
+
return await this.get(`/admin/v1/games/${encodeURIComponent(await this.gameId())}/quota`);
|
|
206
|
+
}
|
|
204
207
|
async listEventCatalog(days = 30, diagnostics = true) {
|
|
205
208
|
const params = new URLSearchParams({ days: String(days), diagnostics: diagnostics ? "1" : "0" });
|
|
206
209
|
return await this.get(`/admin/v1/games/${encodeURIComponent(await this.gameId())}/events/catalog?${params.toString()}`);
|
|
@@ -49,6 +49,12 @@ export async function handleDynamicConfig(client, args, global) {
|
|
|
49
49
|
const key = optionalString(definition.key);
|
|
50
50
|
if (!key)
|
|
51
51
|
throw new Error("dynamic config definition.key is required");
|
|
52
|
+
if (definition.reportPack !== undefined) {
|
|
53
|
+
throw new Error("dynamic config definition.reportPack is no longer supported; inputs must reference the current Report Pack v2");
|
|
54
|
+
}
|
|
55
|
+
if (!Array.isArray(definition.inputs) || definition.inputs.length === 0) {
|
|
56
|
+
throw new Error("dynamic config definition.inputs must be a non-empty array");
|
|
57
|
+
}
|
|
52
58
|
const body = { ...definition };
|
|
53
59
|
delete body.key;
|
|
54
60
|
const scriptPath = optionalString(flags.script);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { parseFlags } from "../args.js";
|
|
2
|
+
import { printResult } from "../output.js";
|
|
3
|
+
import { writeTextFile } from "../resources.js";
|
|
4
|
+
export async function handleQuota(client, args, global) {
|
|
5
|
+
const flags = parseFlags(args);
|
|
6
|
+
if (args.length)
|
|
7
|
+
throw new Error("usage: gamealgo quota [--out quota.json]");
|
|
8
|
+
const value = await client.getGameQuota();
|
|
9
|
+
if (flags.out) {
|
|
10
|
+
const filePath = String(flags.out);
|
|
11
|
+
await writeTextFile(filePath, JSON.stringify(value, null, 2) + "\n");
|
|
12
|
+
await printResult({ ok: true, out: filePath }, global);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
await printResult(value, global);
|
|
16
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -7,6 +7,7 @@ import { handleIntegration } from "./commands/integration.js";
|
|
|
7
7
|
import { handleGameKey } from "./commands/keys.js";
|
|
8
8
|
import { handleMarketing } from "./commands/marketing.js";
|
|
9
9
|
import { handleOptimize } from "./commands/optimize.js";
|
|
10
|
+
import { handleQuota } from "./commands/quota.js";
|
|
10
11
|
import { handleReport } from "./commands/report.js";
|
|
11
12
|
import { handleFileResource } from "./commands/resources.js";
|
|
12
13
|
import { handleSkill } from "./commands/skill.js";
|
|
@@ -95,6 +96,10 @@ export async function main() {
|
|
|
95
96
|
await handleEvents(client, args, global);
|
|
96
97
|
return;
|
|
97
98
|
}
|
|
99
|
+
if (command === "quota") {
|
|
100
|
+
await handleQuota(client, args, global);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
98
103
|
if (command === "integration") {
|
|
99
104
|
await handleIntegration(client, args, global);
|
|
100
105
|
return;
|
package/package.json
CHANGED
package/skills/gamealgo/SKILL.md
CHANGED
|
@@ -114,11 +114,16 @@ After approval, update the actual emission call sites and their normal-flow test
|
|
|
114
114
|
|
|
115
115
|
## Bound Custom Event Volume
|
|
116
116
|
|
|
117
|
-
Before adding or changing
|
|
117
|
+
Before adding or changing any event, run `gamealgo quota --json` and `gamealgo events list --days 30 --json`. Treat the returned effective plan and `ordinaryEvents.dailyLimitPerUser` as a hard per-game, per-user, per-UTC-day budget shared by standard and custom ordinary events. Estimate the user's total ordinary event volume across all existing and proposed call sites, leave headroom for normal retries and future events, and reduce or aggregate high-frequency telemetry before implementation when the bound can reach the current limit.
|
|
118
|
+
|
|
119
|
+
Prefer a protocol-standard event or an existing custom event with the same meaning. Keep the event type stable and put variable values in payload fields; never generate event types from item IDs, levels, timestamps, user input, or other runtime values.
|
|
118
120
|
|
|
119
121
|
Inspect every call site for render/update loops, timers, polling, transport retries, duplicate lifecycle callbacks, and re-entrant listeners. State the trigger boundary and estimate the maximum calls per user, session, context, and active user-day. Use the game's active-user estimate to describe the expected daily volume when it is available.
|
|
120
122
|
|
|
121
123
|
- Standard SDK semantic events are governed by their protocol semantics. Do not disguise custom telemetry as a standard event to bypass safeguards.
|
|
124
|
+
- `purchase` and `ad_view` are exempt only when they represent their real protocol semantics and pass their strict validation. Every other accepted event consumes the ordinary daily budget, including standard events and repeated `eventId` submissions.
|
|
125
|
+
- `quota.today.filteredEvents` is the number of ordinary events actually rejected by quota enforcement today; `shadowWouldRejectEvents` is observation-only and must not be reported as data loss. If actual filtering is nonzero, identify and fix the highest-frequency emission paths before proposing more events.
|
|
126
|
+
- The quota resets at UTC midnight, not the player's local midnight. If quota information is unavailable, do not assume Free, Enterprise, or unlimited capacity; report the missing prerequisite and avoid publishing a higher-volume telemetry design.
|
|
122
127
|
- The SDK limits custom events to 1,000 occurrences per `context × eventType`, 5,000 total occurrences per context, and 100 distinct custom event types per context.
|
|
123
128
|
- A custom event with an unbounded trigger or an expected rate above 1,000 calls per context requires explicit developer review before implementation. Explain the expected volume, storage and processing impact, and the guard that makes the trigger bounded.
|
|
124
129
|
- Never add client-side retries around `track`, rename an event after rejection, remove its custom-event prefix, declare it standard, raise a safety limit, or call a lower-level transport to bypass a quota.
|
|
@@ -128,14 +133,15 @@ Before delivery, report the estimated bound, normal-flow tests, the limiting loo
|
|
|
128
133
|
|
|
129
134
|
## Treat Dynamic Config As A Production Publisher
|
|
130
135
|
|
|
131
|
-
A dynamic config pipeline is Server-side automation that turns
|
|
136
|
+
A dynamic config pipeline is Server-side automation that turns current Report Pack v2 ordinary Dataset snapshots into a live config file. It does not authorize SDK changes, detailed production-data downloads, or live publication by itself.
|
|
132
137
|
|
|
133
138
|
- Define bounded aggregate inputs with Report Pack syntax. Keep filters, joins, aggregation, and data reduction in the managed query rather than passing event detail to JavaScript.
|
|
134
139
|
- Keep transforms synchronous and deterministic. They may use only the supplied datasets, previous output, and scheduled metadata; never depend on network, filesystem, environment variables, wall-clock APIs, randomness, async functions, or Promise output.
|
|
135
140
|
- The output file name and content type belong to the reviewed pipeline definition. The script may return only file content and JSON diagnostics.
|
|
136
141
|
- Before publishing or materially updating an active pipeline, show the target game, input reports and windows, complete script diff, output file and content type, schedule, expected behavior, failure behavior, and user-facing or operational risks. Obtain explicit approval for that exact publication unless the user already gave it after seeing those details.
|
|
137
142
|
- Prefer a disabled pipeline or a local script test while details are still under discussion. After an authorized publish, trigger one run, inspect the persisted run result and generated file version, and confirm that an unchanged second run is hash-deduplicated before treating the automation as verified.
|
|
138
|
-
- Do not
|
|
143
|
+
- Do not embed a Report Pack, use Advanced Query/raw SQL, or trigger warehouse queries from Dynamic Config. Inputs reuse v2 View aggregation over already-materialized ordinary Datasets and pin the Dataset fingerprint at publish time.
|
|
144
|
+
- Do not raise the 1 MiB script/input/output caps, the 100-row per-input cap, the 500-row total cap, the 5-second execution cap, or the minimum daily schedule to bypass a failing design. Reduce the ordinary Dataset/View result or simplify the transform.
|
|
139
145
|
|
|
140
146
|
Use `gamealgo dynamic-config list|get|publish|run|runs` for lifecycle operations. Dynamic config output continues through the ordinary SDK config-file delivery mechanism, so do not change client SDK code merely to consume a generated file that already uses the existing config API.
|
|
141
147
|
|