typefaster-cli 0.1.2__tar.gz → 0.1.4__tar.gz

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.
Files changed (145) hide show
  1. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/PKG-INFO +13 -1
  2. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/README.md +12 -0
  3. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/__init__.py +1 -1
  4. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/net/token_store.py +1 -1
  5. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/online_race.py +4 -7
  6. typefaster_cli-0.1.4/docs/INSTALL.md +64 -0
  7. typefaster_cli-0.1.4/docs/deploy-oracle.md +89 -0
  8. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/pyproject.toml +1 -1
  9. typefaster_cli-0.1.4/scripts/deploy-oracle.sh +76 -0
  10. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.dockerignore +0 -0
  11. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.env.example +0 -0
  12. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  13. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  14. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  15. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  16. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.github/dependabot.yml +0 -0
  17. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.github/workflows/ci.yml +0 -0
  18. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.github/workflows/codeql.yml +0 -0
  19. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.github/workflows/release.yml +0 -0
  20. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/.gitignore +0 -0
  21. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/CONTRIBUTING.md +0 -0
  22. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/LICENSE +0 -0
  23. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/Makefile +0 -0
  24. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/SECURITY.md +0 -0
  25. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/Dockerfile +0 -0
  26. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/__main__.py +0 -0
  27. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/assets/__init__.py +0 -0
  28. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/assets/quotes.json +0 -0
  29. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/cli.py +0 -0
  30. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/domain/__init__.py +0 -0
  31. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/domain/anti_cheat.py +0 -0
  32. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/domain/calculators.py +0 -0
  33. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/domain/errors.py +0 -0
  34. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/domain/ghost.py +0 -0
  35. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/domain/models.py +0 -0
  36. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/domain/typing_engine.py +0 -0
  37. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/__init__.py +0 -0
  38. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/clock.py +0 -0
  39. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/config.py +0 -0
  40. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/db.py +0 -0
  41. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/migrations.py +0 -0
  42. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/paths.py +0 -0
  43. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/quote_loader.py +0 -0
  44. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/replay_store.py +0 -0
  45. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/repository.py +0 -0
  46. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/infra/sqlite_repository.py +0 -0
  47. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/net/__init__.py +0 -0
  48. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/net/api.py +0 -0
  49. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/net/commands.py +0 -0
  50. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/services/__init__.py +0 -0
  51. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/services/container.py +0 -0
  52. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/services/daily_service.py +0 -0
  53. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/services/ghost_service.py +0 -0
  54. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/services/profile_service.py +0 -0
  55. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/services/race_service.py +0 -0
  56. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/services/stats_service.py +0 -0
  57. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/__init__.py +0 -0
  58. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/app.py +0 -0
  59. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/online_app.py +0 -0
  60. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/__init__.py +0 -0
  61. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/_base.py +0 -0
  62. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/daily.py +0 -0
  63. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/help.py +0 -0
  64. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/history.py +0 -0
  65. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/leaderboard.py +0 -0
  66. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/main_menu.py +0 -0
  67. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/practice.py +0 -0
  68. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/profile.py +0 -0
  69. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/race.py +0 -0
  70. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/results.py +0 -0
  71. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/settings.py +0 -0
  72. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/screens/stats.py +0 -0
  73. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/theme.py +0 -0
  74. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/widgets/__init__.py +0 -0
  75. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/widgets/bigtext.py +0 -0
  76. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/widgets/live_stats.py +0 -0
  77. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/widgets/progress_bars.py +0 -0
  78. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/client/typefaster/ui/widgets/typing_field.py +0 -0
  79. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docker-compose.yml +0 -0
  80. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/RELEASING.md +0 -0
  81. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/api-spec.md +0 -0
  82. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/architecture.md +0 -0
  83. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/deploy-fly.md +0 -0
  84. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/deployment.md +0 -0
  85. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/online-setup.md +0 -0
  86. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/redis-schema.md +0 -0
  87. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/roadmap.md +0 -0
  88. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/sqlite-schema.md +0 -0
  89. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/ui-design.md +0 -0
  90. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/docs/websocket-protocol.md +0 -0
  91. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/fly.toml +0 -0
  92. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/infra/README.md +0 -0
  93. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/infra/nginx/nginx.conf +0 -0
  94. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/infra/redis/redis.conf +0 -0
  95. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/packaging/homebrew/typefaster.rb +0 -0
  96. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/scripts/seed_quotes.py +0 -0
  97. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/Dockerfile +0 -0
  98. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/__init__.py +0 -0
  99. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/config.py +0 -0
  100. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/deps.py +0 -0
  101. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/logging_config.py +0 -0
  102. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/main.py +0 -0
  103. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/quotes.py +0 -0
  104. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/redis_keys.py +0 -0
  105. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/repositories.py +0 -0
  106. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/routers/__init__.py +0 -0
  107. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/routers/auth.py +0 -0
  108. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/routers/health.py +0 -0
  109. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/routers/leaderboards.py +0 -0
  110. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/routers/lobbies.py +0 -0
  111. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/routers/oauth.py +0 -0
  112. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/security.py +0 -0
  113. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/ws/__init__.py +0 -0
  114. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/app/ws/manager.py +0 -0
  115. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/pyproject.toml +0 -0
  116. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/tests/__init__.py +0 -0
  117. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/tests/conftest.py +0 -0
  118. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/tests/test_auth.py +0 -0
  119. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/tests/test_health_leaderboards.py +0 -0
  120. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/tests/test_lobbies.py +0 -0
  121. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/tests/test_oauth.py +0 -0
  122. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/tests/test_scoring_anticheat.py +0 -0
  123. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/server/tests/test_ws_race.py +0 -0
  124. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/shared/pyproject.toml +0 -0
  125. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/shared/typefaster_shared/__init__.py +0 -0
  126. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/shared/typefaster_shared/anti_cheat.py +0 -0
  127. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/shared/typefaster_shared/dto.py +0 -0
  128. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/shared/typefaster_shared/events.py +0 -0
  129. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/shared/typefaster_shared/scoring.py +0 -0
  130. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/conftest.py +0 -0
  131. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/fixtures/.gitkeep +0 -0
  132. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/integration/test_container_and_cli.py +0 -0
  133. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/integration/test_migrations.py +0 -0
  134. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/integration/test_profile_stats.py +0 -0
  135. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/integration/test_race_service.py +0 -0
  136. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/integration/test_race_timing.py +0 -0
  137. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/integration/test_sqlite_repository.py +0 -0
  138. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/integration/test_ui_smoke.py +0 -0
  139. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/unit/test_anti_cheat.py +0 -0
  140. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/unit/test_calculators.py +0 -0
  141. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/unit/test_config.py +0 -0
  142. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/unit/test_ghost.py +0 -0
  143. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/unit/test_net.py +0 -0
  144. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/unit/test_quote_loader.py +0 -0
  145. {typefaster_cli-0.1.2 → typefaster_cli-0.1.4}/tests/unit/test_typing_engine.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: typefaster-cli
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: A terminal-first typing game inspired by MonkeyType and TypeRacer.
5
5
  Project-URL: Homepage, https://github.com/Anoshor/typefaster-cli
6
6
  Project-URL: Repository, https://github.com/Anoshor/typefaster-cli
@@ -47,6 +47,18 @@ typefaster
47
47
 
48
48
  …and you're racing within seconds. No login, no server, no Docker, no internet required.
49
49
 
50
+ ## Install
51
+
52
+ ```bash
53
+ # Homebrew
54
+ brew install Anoshor/typefaster/typefaster
55
+
56
+ # or pipx (any OS)
57
+ pipx install typefaster-cli
58
+
59
+ typefaster # play
60
+ ```
61
+
50
62
  ---
51
63
 
52
64
  ## What Phase 1 delivers
@@ -15,6 +15,18 @@ typefaster
15
15
 
16
16
  …and you're racing within seconds. No login, no server, no Docker, no internet required.
17
17
 
18
+ ## Install
19
+
20
+ ```bash
21
+ # Homebrew
22
+ brew install Anoshor/typefaster/typefaster
23
+
24
+ # or pipx (any OS)
25
+ pipx install typefaster-cli
26
+
27
+ typefaster # play
28
+ ```
29
+
18
30
  ---
19
31
 
20
32
  ## What Phase 1 delivers
@@ -1,3 +1,3 @@
1
1
  """TYPEFASTER-CLI — a terminal-first typing game."""
2
2
 
3
- __version__ = "0.1.2"
3
+ __version__ = "0.1.4"
@@ -18,7 +18,7 @@ class Session:
18
18
  # Default points at the public TYPEFASTER server so a fresh install can
19
19
  # register/play with zero config. Override with `typefaster config set-server`
20
20
  # (e.g. a local server or your own deployment).
21
- server_url: str = "https://typefaster-cli.fly.dev"
21
+ server_url: str = "http://140.245.248.113:8000"
22
22
  token: str | None = None
23
23
  username: str | None = None
24
24
 
@@ -307,11 +307,8 @@ class OnlineRaceScreen(Screen[None]):
307
307
 
308
308
  # ── exit ───────────────────────────────────────────────────────────
309
309
  def action_leave(self) -> None:
310
+ # This screen IS the whole online app, so leaving exits cleanly back to
311
+ # the shell (popping the only screen would leave a blank screen). The
312
+ # server removes us from the lobby when the WebSocket closes on exit.
310
313
  self.run_worker(self._send("LEAVE"), name="leave")
311
- if self._ws is not None:
312
- self.run_worker(self._close_ws(), name="close")
313
- self.app.pop_screen()
314
-
315
- async def _close_ws(self) -> None:
316
- with contextlib.suppress(Exception):
317
- await self._ws.close()
314
+ self.app.exit()
@@ -0,0 +1,64 @@
1
+ # Installing & playing TYPEFASTER
2
+
3
+ A terminal typing game. Works offline instantly; multiplayer if you point it at
4
+ a server.
5
+
6
+ ## Install
7
+
8
+ **Homebrew (macOS / Linux):**
9
+ ```bash
10
+ brew install Anoshor/typefaster/typefaster
11
+ ```
12
+
13
+ **pipx (any OS with Python 3.11+):**
14
+ ```bash
15
+ pipx install typefaster-cli
16
+ ```
17
+
18
+ Verify:
19
+ ```bash
20
+ typefaster version
21
+ ```
22
+
23
+ ## Play offline (no account, no internet)
24
+ ```bash
25
+ typefaster # main menu — Quick Race, Time Attack, Practice, Daily…
26
+ typefaster race # jump straight into a quote race
27
+ typefaster race --mode time --time 60
28
+ typefaster stats # your progress
29
+ ```
30
+
31
+ ## Play online (multiplayer)
32
+ The client ships pointing at the public server by default, so:
33
+ ```bash
34
+ typefaster register <name> # create an account (password)
35
+ # or social login:
36
+ typefaster login --github
37
+ typefaster login --google
38
+
39
+ typefaster lobby create --name Friday --time 60 # host a lobby (shows a join code)
40
+ typefaster lobby join ABC123 # friends join with the code
41
+ typefaster lobby list # browse public lobbies
42
+ typefaster leaderboard global # global | daily | weekly
43
+ ```
44
+ In the lobby waiting room, press **R** to ready; the server starts the race when
45
+ everyone is ready. Press **Esc** to leave.
46
+
47
+ Point at a different server (self-hosted / local):
48
+ ```bash
49
+ typefaster config set-server https://your-server.example.com
50
+ typefaster config show
51
+ ```
52
+
53
+ ## Update
54
+ ```bash
55
+ brew upgrade typefaster # Homebrew
56
+ pipx upgrade typefaster-cli # pipx
57
+ ```
58
+
59
+ ## Uninstall
60
+ ```bash
61
+ brew uninstall typefaster
62
+ # or
63
+ pipx uninstall typefaster-cli
64
+ ```
@@ -0,0 +1,89 @@
1
+ # Deploy the server on an Oracle Cloud Always-Free VM ($0 forever)
2
+
3
+ A real 24/7 server on Oracle's Always-Free ARM VM. No ongoing cost.
4
+
5
+ You do the **console steps** (account + VM + open a port). Then a **single
6
+ command** on the VM deploys everything (`scripts/deploy-oracle.sh`).
7
+
8
+ ---
9
+
10
+ ## 1. Create the account
11
+ 1. Go to <https://www.oracle.com/cloud/free/> → **Start for free**.
12
+ 2. Sign up. A credit/debit card is required for identity verification — Oracle
13
+ **does not charge** Always-Free resources. Pick your home region close to you
14
+ (you can't change it later).
15
+
16
+ ## 2. Create an Always-Free VM
17
+ 1. Console → **Menu → Compute → Instances → Create instance**.
18
+ 2. **Image & shape → Edit shape**:
19
+ - Shape series: **Ampere (Arm)** → `VM.Standard.A1.Flex`
20
+ - Set **1 OCPU / 6 GB** (well within the free allowance; plenty for this).
21
+ - *(If Ampere shows "out of capacity", try another availability domain, or use
22
+ the AMD `VM.Standard.E2.1.Micro` Always-Free shape instead.)*
23
+ 3. **Image**: Canonical **Ubuntu 22.04** (or 24.04).
24
+ 4. **Networking**: keep the default VCN; ensure **"Assign a public IPv4 address"** is on.
25
+ 5. **SSH keys**: choose **Generate a key pair** and **download the private key**
26
+ (or paste your own public key).
27
+ 6. **Create**. When it's running, copy the **Public IP address**.
28
+
29
+ ## 3. Open the game port (VCN Security List)
30
+ Oracle blocks inbound by default — open TCP **8000**:
31
+ 1. Instance page → **Virtual cloud network** link → **Security Lists** →
32
+ **Default Security List**.
33
+ 2. **Add Ingress Rules**:
34
+ - Source CIDR: `0.0.0.0/0`
35
+ - IP Protocol: **TCP**
36
+ - Destination Port Range: `8000`
37
+ - **Add**.
38
+
39
+ ## 4. SSH in and deploy (one command)
40
+ ```bash
41
+ chmod 400 ~/Downloads/your-key.key # the key you downloaded
42
+ ssh -i ~/Downloads/your-key.key ubuntu@<PUBLIC_IP>
43
+
44
+ # on the VM:
45
+ curl -fsSL https://raw.githubusercontent.com/Anoshor/typefaster-cli/main/scripts/deploy-oracle.sh | bash
46
+ ```
47
+ The script installs Docker, builds the stack, opens the OS firewall, and prints:
48
+ ```
49
+ Public: http://<PUBLIC_IP>:8000/healthz
50
+ ```
51
+ Check it from your laptop:
52
+ ```bash
53
+ curl http://<PUBLIC_IP>:8000/healthz # {"status":"ok"}
54
+ ```
55
+
56
+ ## 5. Play
57
+ ```bash
58
+ typefaster config set-server http://<PUBLIC_IP>:8000
59
+ typefaster register <name>
60
+ typefaster lobby create --name Friday --time 60
61
+ ```
62
+ Multiplayer runs over `ws://` (works fine). Share the IP + `config set-server`
63
+ line with friends.
64
+
65
+ > Want the client to default to your server (so nobody needs `config set-server`)?
66
+ > Tell me the public IP/domain and I'll bake it in and ship a new release.
67
+
68
+ ---
69
+
70
+ ## Optional: free HTTPS + stable hostname (DuckDNS + Caddy)
71
+ Plain `http://IP` works, but for a tidy `https://you.duckdns.org`:
72
+ 1. Get a free subdomain at <https://www.duckdns.org> and point it at your VM IP.
73
+ 2. On the VM, run Caddy as a reverse proxy (auto Let's Encrypt):
74
+ ```bash
75
+ sudo docker run -d --name caddy --restart unless-stopped --network host \
76
+ caddy caddy reverse-proxy --from you.duckdns.org --to :8000
77
+ ```
78
+ 3. Open TCP **80** and **443** in the VCN Security List too.
79
+ 4. Players: `typefaster config set-server https://you.duckdns.org` (uses `wss://`).
80
+
81
+ ## Updating later
82
+ ```bash
83
+ ssh -i key ubuntu@<IP> 'curl -fsSL https://raw.githubusercontent.com/Anoshor/typefaster-cli/main/scripts/deploy-oracle.sh | bash'
84
+ ```
85
+
86
+ ## Stop / costs
87
+ Always-Free resources don't expire as long as the account stays in good standing.
88
+ To stop: `sudo docker compose down` in `/opt/typefaster`. No charges for the
89
+ Always-Free shapes.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "typefaster-cli"
7
- version = "0.1.2"
7
+ version = "0.1.4"
8
8
  description = "A terminal-first typing game inspired by MonkeyType and TypeRacer."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env bash
2
+ # One-shot TYPEFASTER server deploy for a fresh Ubuntu VM (Oracle Always-Free,
3
+ # or any Ubuntu host). Installs Docker, fetches the repo, and starts the stack.
4
+ #
5
+ # Run it on the VM (as the default user, e.g. `ubuntu`):
6
+ # curl -fsSL https://raw.githubusercontent.com/Anoshor/typefaster-cli/main/scripts/deploy-oracle.sh | bash
7
+ #
8
+ # Re-running it safely updates to the latest code and restarts the stack.
9
+ set -euo pipefail
10
+
11
+ REPO="https://github.com/Anoshor/typefaster-cli"
12
+ DIR="/opt/typefaster"
13
+ PORT="${SERVER_PORT:-8000}"
14
+
15
+ echo "==> Installing prerequisites (git, openssl, iptables-persistent)…"
16
+ sudo apt-get update -y
17
+ sudo DEBIAN_FRONTEND=noninteractive apt-get install -y git openssl ca-certificates curl
18
+
19
+ echo "==> Installing Docker (if missing)…"
20
+ if ! command -v docker >/dev/null 2>&1; then
21
+ curl -fsSL https://get.docker.com | sudo sh
22
+ fi
23
+ sudo systemctl enable --now docker
24
+
25
+ echo "==> Fetching the repo into ${DIR}…"
26
+ sudo mkdir -p "$DIR"
27
+ sudo chown "$USER" "$DIR"
28
+ if [ -d "$DIR/.git" ]; then
29
+ git -C "$DIR" pull --ff-only
30
+ else
31
+ git clone "$REPO" "$DIR"
32
+ fi
33
+ cd "$DIR"
34
+
35
+ echo "==> Writing .env (random JWT secret) if absent…"
36
+ if [ ! -f .env ]; then
37
+ cat > .env <<EOF
38
+ TYPEFASTER_JWT_SECRET=$(openssl rand -hex 32)
39
+ TYPEFASTER_CORS_ORIGINS=*
40
+ TYPEFASTER_ACCESS_TOKEN_MINUTES=1440
41
+ SERVER_PORT=${PORT}
42
+ EOF
43
+ fi
44
+
45
+ echo "==> Opening port ${PORT} on the OS firewall (Oracle Ubuntu blocks by default)…"
46
+ # Oracle's Ubuntu images ship iptables rules that REJECT inbound. Insert ACCEPT.
47
+ if sudo iptables -C INPUT -p tcp --dport "${PORT}" -j ACCEPT 2>/dev/null; then
48
+ echo " (rule already present)"
49
+ else
50
+ sudo iptables -I INPUT -p tcp --dport "${PORT}" -j ACCEPT
51
+ fi
52
+ sudo DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent >/dev/null 2>&1 || true
53
+ sudo netfilter-persistent save >/dev/null 2>&1 || true
54
+
55
+ echo "==> Building & starting the stack…"
56
+ sudo docker compose up -d --build
57
+
58
+ echo "==> Waiting for health…"
59
+ for _ in $(seq 1 40); do
60
+ if curl -fsS "http://127.0.0.1:${PORT}/healthz" >/dev/null 2>&1; then break; fi
61
+ sleep 2
62
+ done
63
+
64
+ IP="$(curl -fsS ifconfig.me 2>/dev/null || echo '<this-vm-public-ip>')"
65
+ echo
66
+ echo "============================================================"
67
+ echo " TYPEFASTER server is up."
68
+ echo " Local : http://127.0.0.1:${PORT}/healthz"
69
+ echo " Public: http://${IP}:${PORT}/healthz"
70
+ echo
71
+ echo " Players point their CLI at it with:"
72
+ echo " typefaster config set-server http://${IP}:${PORT}"
73
+ echo
74
+ echo " IMPORTANT: also add an Ingress rule for TCP ${PORT} (source 0.0.0.0/0)"
75
+ echo " in your VCN Security List in the Oracle console, or it won't be reachable."
76
+ echo "============================================================"
File without changes
File without changes
File without changes