@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 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
- Hosting the page is free. What the game's server, saves and scores may use is the game's plan:
527
-
528
- | | Free | Creator | Scale |
529
- | -------------------- | ------------------------------------------------------------------ | --------------------------------------------------------- | ----------------------- |
530
- | For | every game, by default | a game in one of your paid game slots (per game, a month) | granted by xgames.fun |
531
- | 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 |
532
- | 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 |
533
- | Use included a month | $1 | $10 a slot, shared by your Creator games | as granted |
534
- | Sites that embed it | 3 (`xcore embed`) | 10 | 25 |
535
- | Domains of your own | none | 1 (`xcore domain`) | 5 |
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. Slots are $15 for 30
539
- days, prepaid in SOL or USDC in xgames.fun Studio (Plans; no automatic renewal, 7 days' grace after the period ends).
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 game slots: 200 ms a request, 6,000 requests a minute, 1 GB of saves, and
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
- A slot is $15 for 30 days, prepaid in SOL or USDC on xgames.fun (Studio → Plans; no automatic renewal), and moves
21
- between your games at any time without changing the bill. Usage credit, bought the same way, lets Creator games go
22
- past what their slots include (at twice what xgames.fun pays) instead of slowing down.
23
- activate put this folder's game in a free slot
24
- deactivate take it out (it goes back to Free and the slot is free for another game)
25
- --all your slots and every game's plan`;
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
- `${e.message} Free one with ${CMD} plan deactivate <another game>, or buy a slot on xgames.fun (Studio → Plans, in SOL or USDC).`,
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
- ? 'Out of its slot: Free from its next request, and the slot is free.'
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;
@@ -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
@@ -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
- // GET /api/kit/plan → {ok, slots, used, billing, capCents, monthCents, includedCents, games}
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(` game slots: ${r.used ?? 0} of ${r.slots} in use`);
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: Studio → Plans, in ${(r.payments.currencies ?? ['SOL', 'USDC']).join(' or ')}${r.payments.cluster === 'devnet' ? ', devnet test payments' : ''})`
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
- `Game slots: ${r.used ?? 0} of ${r.slots ?? 0} in use${until}${how}`,
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.0",
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 game slot makes it Creator
169
- (`xcore plan activate <folder>` once they have a slot), and the slot moves between their games at any time. Never
170
- activate or deactivate a game without asking.
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