@xgamesfun/xcore 0.2.0 → 0.2.1
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 +18 -14
- package/commands/plan.mjs +16 -13
- package/commands/publish.mjs +10 -0
- package/lib/publish/plans.mjs +13 -4
- package/package.json +1 -1
- package/skills/bring-your-own-game/SKILL.md +4 -3
package/README.md
CHANGED
|
@@ -523,24 +523,28 @@ games. `GAMESFUN_STUDIO=<origin>` publishes to another xgames.fun (a Studio on y
|
|
|
523
523
|
|
|
524
524
|
### Its plan: `xcore plan`
|
|
525
525
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
|
532
|
-
|
|
|
533
|
-
|
|
|
534
|
-
|
|
|
535
|
-
|
|
|
526
|
+
Every game sits in a **slot**. Everyone gets **2 free slots**, whose games run on Free; any more games need a **paid
|
|
527
|
+
slot** ($15 for 30 days), whose game runs on Creator. A new game is refused while both free slots are taken: archive one
|
|
528
|
+
you no longer need (on your console, xgames.fun/console; unpublish it first) or move one to a paid slot. Archived games
|
|
529
|
+
free their slot unless their link is still live. What the game's server, saves and scores may use is its plan:
|
|
530
|
+
|
|
531
|
+
| | Free | Creator | Scale |
|
|
532
|
+
| -------------------- | ------------------------------------------------------------------ | ---------------------------------------------------- | ----------------------- |
|
|
533
|
+
| For | a game in one of your 2 free slots | a game in one of your paid slots (per game, a month) | granted by xgames.fun |
|
|
534
|
+
| Server | 50 ms of CPU a request; 600 requests a minute, 120 from one player | 200 ms; 6,000 a minute, 600 from one player | 1,000 ms; 30,000, 1,200 |
|
|
535
|
+
| Saves and scores | 10 MB of saves; 8 boards of 10,000 entries | 1 GB; 16 boards of 1,000,000 | 10 GB; 16 of 1,000,000 |
|
|
536
|
+
| Use included a month | $1 | $10 a slot, shared by your Creator games | as granted |
|
|
537
|
+
| Sites that embed it | 3 (`xcore embed`) | 10 | 25 |
|
|
538
|
+
| Domains of your own | none | 1 (`xcore domain`) | 5 |
|
|
536
539
|
|
|
537
540
|
Past what is included, a game is **capped** until the month ends: its server answers at most 60 requests a minute (20
|
|
538
|
-
from one player) and saves and scores slow down, but nothing is lost and the game keeps working.
|
|
539
|
-
days, prepaid in SOL or USDC
|
|
541
|
+
from one player) and saves and scores slow down, but nothing is lost and the game keeps working. Paid slots are $15 for
|
|
542
|
+
30 days, prepaid in SOL or USDC on xgames.fun (your console → Plans; no automatic renewal, 7 days' grace after the period
|
|
543
|
+
ends; when they end, their games go back to free slots and nothing is taken down).
|
|
540
544
|
Usage credit, bought the same way, lets Creator games go past what their slots include, at twice what xgames.fun pays,
|
|
541
|
-
instead of slowing down. A slot moves between your games at any time
|
|
545
|
+
instead of slowing down. A paid slot moves between your games at any time
|
|
542
546
|
(`xcore plan deactivate <one>`, `xcore plan activate <another>`) without changing the bill. `xcore plan [folder]`
|
|
543
|
-
shows a game's plan, its limits and this month's use; `--all` your slots and every game. A game's server sees a 429
|
|
547
|
+
shows a game's plan, its limits and this month's use; `--all` your free and paid slots and every game. A game's server sees a 429
|
|
544
548
|
with `scope` (`"player"` or `"game"`) and `plan` when it goes past a rate.
|
|
545
549
|
|
|
546
550
|
### Your own site and your own domain: `xcore embed`, `xcore domain`
|
package/commands/plan.mjs
CHANGED
|
@@ -12,17 +12,18 @@ const usage = `Usage: xcore plan [dir] [--json]
|
|
|
12
12
|
What a game's backend may use on xgames.fun (its server, saves and scores), and what it used this month.
|
|
13
13
|
Free every game, by default: a small server (50 ms of CPU a request, 600 requests a minute) and $1 of use a
|
|
14
14
|
month; past that its server is capped (slow) until the month ends
|
|
15
|
-
Creator a game in one of your paid
|
|
16
|
-
$10 of use a month per slot, shared by your Creator games
|
|
15
|
+
Creator a game in one of your paid slots: 200 ms a request, 6,000 requests a minute, 1 GB of saves, and
|
|
16
|
+
$10 of use a month per paid slot, shared by your Creator games
|
|
17
17
|
Scale granted by xgames.fun for a game that needs more
|
|
18
18
|
Every plan lets sites of yours embed the game (Free 3, Creator 10, Scale 25: ${CMD} embed); Creator and Scale serve
|
|
19
19
|
it on domains of your own (1 and 5: ${CMD} domain).
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
Every game sits in a slot. Everyone gets 2 free slots, whose games run on Free; any more games need a paid slot,
|
|
21
|
+
$15 for 30 days, prepaid in SOL or USDC on xgames.fun (your console → Plans; no automatic renewal), whose game runs on
|
|
22
|
+
Creator. A paid slot moves between your games at any time without changing the bill. Usage credit, bought the same way,
|
|
23
|
+
lets Creator games go past what their slots include (at twice what xgames.fun pays) instead of slowing down.
|
|
24
|
+
activate move this folder's game to a paid slot (its free slot opens for another game)
|
|
25
|
+
deactivate move it back to a free slot (one must be open; its paid slot opens for another game)
|
|
26
|
+
--all your free and paid slots and every game's plan`;
|
|
26
27
|
|
|
27
28
|
export default {
|
|
28
29
|
name: 'plan',
|
|
@@ -57,7 +58,9 @@ export default {
|
|
|
57
58
|
const r = await setActive(dir, verb === 'activate').catch(e => {
|
|
58
59
|
if (e?.status === 409)
|
|
59
60
|
throw new Error(
|
|
60
|
-
|
|
61
|
+
e.code === 'no-free-slot'
|
|
62
|
+
? `${e.message} Archive a game you no longer need on your console (xgames.fun/console), or move another game to a paid slot.`
|
|
63
|
+
: `${e.message} Open one with ${CMD} plan deactivate <another game>, or buy a paid slot on xgames.fun (your console → Plans, in SOL or USDC).`,
|
|
61
64
|
);
|
|
62
65
|
return plain(e);
|
|
63
66
|
});
|
|
@@ -66,11 +69,11 @@ export default {
|
|
|
66
69
|
const what =
|
|
67
70
|
verb === 'activate'
|
|
68
71
|
? r.changed
|
|
69
|
-
? 'In a slot: Creator from its next request.'
|
|
70
|
-
: 'Already in a slot.'
|
|
72
|
+
? 'In a paid slot: Creator from its next request; its free slot is open for another game.'
|
|
73
|
+
: 'Already in a paid slot.'
|
|
71
74
|
: r.changed
|
|
72
|
-
? '
|
|
73
|
-
: 'It was not in a slot.';
|
|
75
|
+
? 'Back in a free slot: Free from its next request, and its paid slot is open for another game.'
|
|
76
|
+
: 'It was not in a paid slot.';
|
|
74
77
|
console.log(`${what}\n${describeGame(r)}`);
|
|
75
78
|
}
|
|
76
79
|
return 0;
|
package/commands/publish.mjs
CHANGED
|
@@ -132,6 +132,16 @@ export function publishCommand({
|
|
|
132
132
|
newGame: values.new,
|
|
133
133
|
title: values.title ?? null,
|
|
134
134
|
progress: values.json ? () => {} : l => console.error(l),
|
|
135
|
+
}).catch(e => {
|
|
136
|
+
// A new game needs one of the account's 2 free slots (xgames.fun's words say so); name the commands that free one.
|
|
137
|
+
if (e?.code === 'no-free-slot')
|
|
138
|
+
throw Object.assign(
|
|
139
|
+
new Error(
|
|
140
|
+
`${e.message}\n ${CMD} plan activate <another game's folder> moves that game to a paid slot\n ${CMD} plan --all your slots and games; archive one on ${origin}/console`,
|
|
141
|
+
),
|
|
142
|
+
{ status: e.status, code: e.code },
|
|
143
|
+
);
|
|
144
|
+
throw e;
|
|
135
145
|
});
|
|
136
146
|
if (values.json) printJson(r);
|
|
137
147
|
else
|
package/lib/publish/plans.mjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// `xcore plan`'s calls to xgames.fun. A plan is a game's backend tier: Free by default (strict), or
|
|
2
2
|
// Creator when its owner puts it in one of their paid game slots (priced per game slot a month; a slot moves between
|
|
3
3
|
// games at any time without changing the bill), or Scale, which xgames.fun's operator grants.
|
|
4
|
-
//
|
|
4
|
+
// Every game sits in a slot: 2 free ones for everyone (their games on Free), any more are paid (their games on Creator).
|
|
5
|
+
// GET /api/kit/plan → {ok, slots, used, billing, capCents, monthCents, includedCents, games,
|
|
6
|
+
// gameSlots?: {free: {slots, used}, paid: {slots, used}, granted, open}}
|
|
7
|
+
// (slots/used: the paid slots; gameSlots: from xgames.fun 2026-11-08)
|
|
5
8
|
// GET /api/kit/games/<gameId>/plan → {ok, game, tier, capped, comp, limits, monthCents, includedCents, slots, used}
|
|
6
9
|
// POST /api/kit/games/<gameId>/plan {"active": bool} → the same, and changed
|
|
7
10
|
// The game is the folder's own (its .gamesfun/publish.json for this Studio); the credential is publish's.
|
|
@@ -69,7 +72,7 @@ export function describeGame(r) {
|
|
|
69
72
|
lines.push(
|
|
70
73
|
' capped: its server answers slowly (60 requests a minute) until the month ends, or until it gets more room',
|
|
71
74
|
);
|
|
72
|
-
if (r.slots !== undefined) lines.push(`
|
|
75
|
+
if (r.slots !== undefined) lines.push(` paid slots: ${r.used ?? 0} of ${r.slots} in use`);
|
|
73
76
|
return lines.join('\n');
|
|
74
77
|
}
|
|
75
78
|
|
|
@@ -78,12 +81,18 @@ export function describeAccount(r) {
|
|
|
78
81
|
const open = r.payments?.on || r.billing;
|
|
79
82
|
const until = r.periodEnd ? `, paid through ${new Date(r.periodEnd).toISOString().slice(0, 10)}` : '';
|
|
80
83
|
const how = r.payments?.on
|
|
81
|
-
? ` (buy or renew on xgames.fun:
|
|
84
|
+
? ` (buy or renew on xgames.fun: your console → Plans, in ${(r.payments.currencies ?? ['SOL', 'USDC']).join(' or ')}${r.payments.cluster === 'devnet' ? ', devnet test payments' : ''})`
|
|
82
85
|
: open
|
|
83
86
|
? ''
|
|
84
87
|
: ' (buying slots is not open on this xgames.fun yet)';
|
|
88
|
+
const s = r.gameSlots;
|
|
85
89
|
const lines = [
|
|
86
|
-
|
|
90
|
+
...(s
|
|
91
|
+
? [
|
|
92
|
+
`Free slots: ${s.free.used} of ${s.free.slots} in use (their games run on Free)${s.open === 0 ? '; a new game needs one: archive a game or move one to a paid slot' : ''}`,
|
|
93
|
+
]
|
|
94
|
+
: []),
|
|
95
|
+
`${s ? 'Paid slots' : 'Game slots'}: ${r.used ?? 0} of ${r.slots ?? 0} in use${s ? ' (their games run on Creator)' : ''}${until}${how}`,
|
|
87
96
|
`This month: ${dollars(r.monthCents)}${r.includedCents == null ? '' : ` of ${dollars(r.includedCents)} included`}${r.creditCents ? `; usage credit ${dollars(r.creditCents)}` : ''}${r.capCents ? `; spending cap ${dollars(r.capCents)}` : ''}`,
|
|
88
97
|
];
|
|
89
98
|
for (const g of r.games ?? [])
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xgamesfun/xcore",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "xgames.fun from the command line: bring a web game you already made, check it as xgames.fun hosts it, give it a backend and a Solana economy, and publish it at a link anyone can play.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"game",
|
|
@@ -165,9 +165,10 @@ nothing checked (their gameplay, their backend's own behaviour).
|
|
|
165
165
|
|
|
166
166
|
A game with a `server/`, saves or scores runs under its **plan** (`xcore plan <folder>`): Free by default (50 ms of CPU
|
|
167
167
|
and 600 requests a minute, $1 of use a month, then capped and slow until the month ends). When the game needs more
|
|
168
|
-
(a server that replays play, many players at once), tell them: a paid
|
|
169
|
-
(`xcore plan activate <folder>` once they have
|
|
170
|
-
|
|
168
|
+
(a server that replays play, many players at once), tell them: a paid slot makes it Creator
|
|
169
|
+
(`xcore plan activate <folder>` once they have one), and the paid slot moves between their games at any time. Everyone
|
|
170
|
+
has 2 free slots: a third game is refused on publish (`no-free-slot`) until they archive one on their console
|
|
171
|
+
(xgames.fun/console) or move one to a paid slot. Never activate, deactivate or archive a game without asking.
|
|
171
172
|
|
|
172
173
|
Their own website can show the game (`xcore embed add https://theirsite.com <folder>` prints the `<iframe>`), and on
|
|
173
174
|
Creator or Scale it can play at their own domain (`xcore domain add play.theirsite.com <folder>` prints two DNS records
|