@javleds/vue-game-engine 0.1.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/LICENSE +21 -0
- package/README.es.md +169 -0
- package/README.md +177 -0
- package/dist/composables/useRoomConnectionLifecycle.d.ts +2 -0
- package/dist/composables/useRoomConnectionLifecycle.d.ts.map +1 -0
- package/dist/composables/useRoomConnectionLifecycle.js +18 -0
- package/dist/composables/useRoomConnectionLifecycle.js.map +1 -0
- package/dist/composables/useRoomRealtime.d.ts +14 -0
- package/dist/composables/useRoomRealtime.d.ts.map +1 -0
- package/dist/composables/useRoomRealtime.js +16 -0
- package/dist/composables/useRoomRealtime.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/realtime/realtimeClient.d.ts +11 -0
- package/dist/realtime/realtimeClient.d.ts.map +1 -0
- package/dist/realtime/realtimeClient.js +11 -0
- package/dist/realtime/realtimeClient.js.map +1 -0
- package/dist/repositories/chatRepository.d.ts +5 -0
- package/dist/repositories/chatRepository.d.ts.map +1 -0
- package/dist/repositories/chatRepository.js +10 -0
- package/dist/repositories/chatRepository.js.map +1 -0
- package/dist/repositories/http.d.ts +5 -0
- package/dist/repositories/http.d.ts.map +1 -0
- package/dist/repositories/http.js +13 -0
- package/dist/repositories/http.js.map +1 -0
- package/dist/repositories/roomsRepository.d.ts +9 -0
- package/dist/repositories/roomsRepository.d.ts.map +1 -0
- package/dist/repositories/roomsRepository.js +44 -0
- package/dist/repositories/roomsRepository.js.map +1 -0
- package/dist/stores/sessionStore.d.ts +28 -0
- package/dist/stores/sessionStore.d.ts.map +1 -0
- package/dist/stores/sessionStore.js +72 -0
- package/dist/stores/sessionStore.js.map +1 -0
- package/dist/types/chat.d.ts +10 -0
- package/dist/types/chat.d.ts.map +1 -0
- package/dist/types/chat.js +2 -0
- package/dist/types/chat.js.map +1 -0
- package/dist/types/room.d.ts +28 -0
- package/dist/types/room.d.ts.map +1 -0
- package/dist/types/room.js +2 -0
- package/dist/types/room.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Javleds
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.es.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Vue Game Engine
|
|
2
|
+
|
|
3
|
+
Paquete frontend reusable para juegos de mesa en linea por turnos usando Vue.
|
|
4
|
+
|
|
5
|
+
Este paquete contiene la capa cliente generica: repositorios HTTP de sala, repositorios de chat, almacenamiento de sesion del jugador, ciclo de conexion de sala y suscripciones realtime. No renderiza un tablero especifico y no contiene reglas de juego.
|
|
6
|
+
|
|
7
|
+
La documentacion principal en ingles esta en [README.md](README.md).
|
|
8
|
+
|
|
9
|
+
## Enlaces de Repositorio
|
|
10
|
+
|
|
11
|
+
Repositorios oficiales:
|
|
12
|
+
|
|
13
|
+
- Paquete frontend Vue: https://github.com/javleds/vue-game-engine
|
|
14
|
+
- Paquete backend Laravel: https://github.com/javleds/laravel-game-engine
|
|
15
|
+
|
|
16
|
+
## Relacion Backend / Frontend
|
|
17
|
+
|
|
18
|
+
`@javleds/vue-game-engine` es la mitad frontend del motor. `javleds/laravel-game-engine` es la mitad backend. El frontend consume endpoints HTTP, guarda la sesion local del jugador y escucha eventos realtime por sala. El backend mantiene el estado autoritativo.
|
|
19
|
+
|
|
20
|
+
```plantuml
|
|
21
|
+
@startuml
|
|
22
|
+
skinparam componentStyle rectangle
|
|
23
|
+
|
|
24
|
+
package "Aplicacion Vue host" {
|
|
25
|
+
[Paginas del juego]
|
|
26
|
+
[Componentes UI]
|
|
27
|
+
[Repositorios de acciones]
|
|
28
|
+
[Setup de Echo]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
package "@javleds/vue-game-engine" {
|
|
32
|
+
[Repositorio de sala]
|
|
33
|
+
[Repositorio de chat]
|
|
34
|
+
[Store de sesion]
|
|
35
|
+
[Composables realtime]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
package "javleds/laravel-game-engine" {
|
|
39
|
+
[Servicios de sala]
|
|
40
|
+
[Servicios de chat]
|
|
41
|
+
[Command Runner]
|
|
42
|
+
[Broadcast events]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
[Paginas del juego] --> [Repositorio de sala]
|
|
46
|
+
[Paginas del juego] --> [Store de sesion]
|
|
47
|
+
[Setup de Echo] --> [Composables realtime]
|
|
48
|
+
[Repositorio de sala] --> [Servicios de sala]
|
|
49
|
+
[Repositorio de chat] --> [Servicios de chat]
|
|
50
|
+
[Broadcast events] --> [Composables realtime]
|
|
51
|
+
@enduml
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Que Resuelve
|
|
55
|
+
|
|
56
|
+
El paquete frontend resuelve:
|
|
57
|
+
|
|
58
|
+
- Llamadas HTTP genericas para crear, unir, salir, iniciar, desconectar y consultar estado de sala.
|
|
59
|
+
- Llamadas HTTP genericas para listar y enviar mensajes de chat.
|
|
60
|
+
- Helper de bearer token para requests por jugador.
|
|
61
|
+
- Store Pinia para datos de reconexion.
|
|
62
|
+
- Suscripciones realtime por sala para cambios de estado y chat.
|
|
63
|
+
- Composable de ciclo de conexion/desconexion.
|
|
64
|
+
- Tipos TypeScript compartidos para sala y chat.
|
|
65
|
+
|
|
66
|
+
La aplicacion host sigue siendo responsable de:
|
|
67
|
+
|
|
68
|
+
- Paginas y componentes Vue.
|
|
69
|
+
- Repositorios de acciones especificas del juego.
|
|
70
|
+
- Tipos TypeScript del estado y comandos del juego.
|
|
71
|
+
- Configurar Laravel Echo u otro cliente realtime compatible.
|
|
72
|
+
- Estilos, rutas y comportamiento de UI.
|
|
73
|
+
|
|
74
|
+
## Instalacion Local
|
|
75
|
+
|
|
76
|
+
Para desarrollo con repos hermanos:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"dependencies": {
|
|
81
|
+
"@javleds/vue-game-engine": "file:../vue-game-engine"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Despues:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Cuando el paquete este publicado en npm, se podra reemplazar el `file:` por una version semantica.
|
|
93
|
+
|
|
94
|
+
## Setup en la App Host
|
|
95
|
+
|
|
96
|
+
Configura el cliente realtime durante el arranque de la app. Laravel Echo es el cliente esperado por defecto:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import Echo from 'laravel-echo'
|
|
100
|
+
import Pusher from 'pusher-js'
|
|
101
|
+
import { configureTurnEngineRealtime } from '@javleds/vue-game-engine'
|
|
102
|
+
|
|
103
|
+
window.Pusher = Pusher
|
|
104
|
+
|
|
105
|
+
const echo = new Echo({
|
|
106
|
+
broadcaster: 'reverb',
|
|
107
|
+
key: import.meta.env.VITE_REVERB_APP_KEY,
|
|
108
|
+
wsHost: import.meta.env.VITE_REVERB_HOST,
|
|
109
|
+
wsPort: Number(import.meta.env.VITE_REVERB_PORT ?? 80),
|
|
110
|
+
wssPort: Number(import.meta.env.VITE_REVERB_PORT ?? 443),
|
|
111
|
+
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
|
|
112
|
+
enabledTransports: ['ws', 'wss'],
|
|
113
|
+
authEndpoint: '/broadcasting/auth',
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
configureTurnEngineRealtime(echo)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Importa ese modulo antes de montar Vue:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import './echo'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Cuando uses paquetes locales enlazados, conserva symlinks para que TypeScript y Vite resuelvan las peer dependencies desde la app host:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"compilerOptions": {
|
|
130
|
+
"preserveSymlinks": true
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
export default defineConfig({
|
|
137
|
+
resolve: {
|
|
138
|
+
preserveSymlinks: true,
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Contrato Backend / Frontend
|
|
144
|
+
|
|
145
|
+
El paquete espera endpoints compatibles con estos flujos:
|
|
146
|
+
|
|
147
|
+
- Ciclo de sala: crear, unir, salir, iniciar, desconectar, reconectar/consultar estado.
|
|
148
|
+
- Chat: listar mensajes y enviar mensaje.
|
|
149
|
+
- Eventos realtime en canales `room.{roomId}`:
|
|
150
|
+
- `.room.state.changed`
|
|
151
|
+
- `.room.chat.message.created`
|
|
152
|
+
|
|
153
|
+
Los comandos especificos del juego quedan fuera del paquete. La app host debe crear su propio repositorio de acciones y puede reutilizar el cliente `http` y el helper `bearer` exportados.
|
|
154
|
+
|
|
155
|
+
## Checklist Para Publicar
|
|
156
|
+
|
|
157
|
+
- Mantener `dist` generado por `npm run build` antes de publicar.
|
|
158
|
+
- Agregar CI para typecheck, build e instalacion de prueba.
|
|
159
|
+
- Crear tag semantico, por ejemplo `v0.1.0`.
|
|
160
|
+
|
|
161
|
+
## Build
|
|
162
|
+
|
|
163
|
+
Este paquete publica JavaScript compilado y declaraciones desde `dist`.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm install
|
|
167
|
+
npm run build
|
|
168
|
+
npm pack --dry-run
|
|
169
|
+
```
|
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Vue Game Engine
|
|
2
|
+
|
|
3
|
+
Reusable Vue client package for online turn-based board games.
|
|
4
|
+
|
|
5
|
+
This package owns the generic frontend client layer: room HTTP repositories, chat repositories, player session storage, room connection lifecycle, and realtime subscriptions. It does not render a specific game board and does not contain game rules.
|
|
6
|
+
|
|
7
|
+
Spanish documentation is available in [README.es.md](README.es.md).
|
|
8
|
+
|
|
9
|
+
## Repository Links
|
|
10
|
+
|
|
11
|
+
Official repositories:
|
|
12
|
+
|
|
13
|
+
- Vue frontend package: https://github.com/javleds/vue-game-engine
|
|
14
|
+
- Laravel backend package: https://github.com/javleds/laravel-game-engine
|
|
15
|
+
|
|
16
|
+
## Package Pair
|
|
17
|
+
|
|
18
|
+
This package is the frontend half of the engine. It is designed to work with the Laravel backend package, `javleds/laravel-game-engine`, through HTTP endpoints and realtime room events.
|
|
19
|
+
|
|
20
|
+
```plantuml
|
|
21
|
+
@startuml
|
|
22
|
+
skinparam componentStyle rectangle
|
|
23
|
+
|
|
24
|
+
package "Host Vue app" {
|
|
25
|
+
[Game Pages]
|
|
26
|
+
[Game UI Components]
|
|
27
|
+
[Game Action Repositories]
|
|
28
|
+
[Echo Setup]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
package "@javleds/vue-game-engine" {
|
|
32
|
+
[Room Repository]
|
|
33
|
+
[Chat Repository]
|
|
34
|
+
[Session Store]
|
|
35
|
+
[Realtime Composables]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
package "javleds/laravel-game-engine" {
|
|
39
|
+
[Room Services]
|
|
40
|
+
[Chat Services]
|
|
41
|
+
[Command Runner]
|
|
42
|
+
[Broadcast Events]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
[Game Pages] --> [Room Repository]
|
|
46
|
+
[Game Pages] --> [Session Store]
|
|
47
|
+
[Game Pages] --> [Realtime Composables]
|
|
48
|
+
[Game Action Repositories] --> [Command Runner]
|
|
49
|
+
[Echo Setup] --> [Realtime Composables]
|
|
50
|
+
[Room Repository] --> [Room Services]
|
|
51
|
+
[Chat Repository] --> [Chat Services]
|
|
52
|
+
[Broadcast Events] --> [Realtime Composables]
|
|
53
|
+
@enduml
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Responsibilities
|
|
57
|
+
|
|
58
|
+
The package provides:
|
|
59
|
+
|
|
60
|
+
- Generic room HTTP calls: create, join, leave, start, disconnect, and fetch state.
|
|
61
|
+
- Generic chat HTTP calls: list and send room messages.
|
|
62
|
+
- Bearer-token helper for room-scoped requests.
|
|
63
|
+
- Pinia session store for player reconnect data.
|
|
64
|
+
- Realtime room subscriptions for state and chat events.
|
|
65
|
+
- Connection lifecycle composable for disconnect keepalive behavior.
|
|
66
|
+
- Shared TypeScript types for room and chat API responses.
|
|
67
|
+
|
|
68
|
+
The host game provides:
|
|
69
|
+
|
|
70
|
+
- Vue pages and components.
|
|
71
|
+
- Game-specific action repositories.
|
|
72
|
+
- Game-specific TypeScript state and command payload types.
|
|
73
|
+
- Laravel Echo or another compatible realtime client.
|
|
74
|
+
- Styling, routing, and UI behavior.
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
For local development with a sibling checkout:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"dependencies": {
|
|
83
|
+
"@javleds/vue-game-engine": "file:../vue-game-engine"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Then run:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm install
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
For npm registry usage, replace the file dependency with the published package version once the repository is published.
|
|
95
|
+
|
|
96
|
+
## Host App Setup
|
|
97
|
+
|
|
98
|
+
Configure the realtime client during app boot. Laravel Echo is the expected default client:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import Echo from 'laravel-echo'
|
|
102
|
+
import Pusher from 'pusher-js'
|
|
103
|
+
import { configureTurnEngineRealtime } from '@javleds/vue-game-engine'
|
|
104
|
+
|
|
105
|
+
window.Pusher = Pusher
|
|
106
|
+
|
|
107
|
+
const echo = new Echo({
|
|
108
|
+
broadcaster: 'reverb',
|
|
109
|
+
key: import.meta.env.VITE_REVERB_APP_KEY,
|
|
110
|
+
wsHost: import.meta.env.VITE_REVERB_HOST,
|
|
111
|
+
wsPort: Number(import.meta.env.VITE_REVERB_PORT ?? 80),
|
|
112
|
+
wssPort: Number(import.meta.env.VITE_REVERB_PORT ?? 443),
|
|
113
|
+
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
|
|
114
|
+
enabledTransports: ['ws', 'wss'],
|
|
115
|
+
authEndpoint: '/broadcasting/auth',
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
configureTurnEngineRealtime(echo)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Import that setup module before mounting Vue.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import './echo'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
When using local linked packages, preserve symlinks so TypeScript and Vite resolve peer dependencies from the host app:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"compilerOptions": {
|
|
132
|
+
"preserveSymlinks": true
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
export default defineConfig({
|
|
139
|
+
resolve: {
|
|
140
|
+
preserveSymlinks: true,
|
|
141
|
+
},
|
|
142
|
+
})
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Backend / Frontend Contract
|
|
146
|
+
|
|
147
|
+
The package expects host endpoints compatible with these flows:
|
|
148
|
+
|
|
149
|
+
- Room lifecycle: create, join, leave, start, disconnect, reconnect/state fetch.
|
|
150
|
+
- Chat lifecycle: list messages and send message.
|
|
151
|
+
- Realtime events on `room.{roomId}` channels:
|
|
152
|
+
- `.room.state.changed`
|
|
153
|
+
- `.room.chat.message.created`
|
|
154
|
+
|
|
155
|
+
Game-specific commands are intentionally outside this package. A game app should create its own action repository and can reuse the exported `http` client and `bearer` helper.
|
|
156
|
+
|
|
157
|
+
## Publishing Checklist
|
|
158
|
+
|
|
159
|
+
Before publishing this package publicly:
|
|
160
|
+
|
|
161
|
+
- Keep `dist` generated by `npm run build` before publishing.
|
|
162
|
+
- Add CI for typecheck, package build, and install smoke tests.
|
|
163
|
+
- Tag a semantic version, for example `v0.1.0`.
|
|
164
|
+
|
|
165
|
+
## Current Status
|
|
166
|
+
|
|
167
|
+
This package is extracted and usable as a local npm file package. It is not tied to the Giants game domain.
|
|
168
|
+
|
|
169
|
+
## Build
|
|
170
|
+
|
|
171
|
+
This package publishes compiled JavaScript and declaration files from `dist`.
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npm install
|
|
175
|
+
npm run build
|
|
176
|
+
npm pack --dry-run
|
|
177
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRoomConnectionLifecycle.d.ts","sourceRoot":"","sources":["../../src/composables/useRoomConnectionLifecycle.ts"],"names":[],"mappings":"AAIA,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,CAkB3F"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { onMounted, onUnmounted } from 'vue';
|
|
2
|
+
import { disconnectRoomKeepalive } from '../repositories/roomsRepository';
|
|
3
|
+
export function useRoomConnectionLifecycle(roomId, token) {
|
|
4
|
+
function notifyDisconnect() {
|
|
5
|
+
const playerToken = token();
|
|
6
|
+
if (!playerToken) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
disconnectRoomKeepalive(roomId, playerToken);
|
|
10
|
+
}
|
|
11
|
+
onMounted(() => {
|
|
12
|
+
window.addEventListener('pagehide', notifyDisconnect);
|
|
13
|
+
});
|
|
14
|
+
onUnmounted(() => {
|
|
15
|
+
window.removeEventListener('pagehide', notifyDisconnect);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=useRoomConnectionLifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRoomConnectionLifecycle.js","sourceRoot":"","sources":["../../src/composables/useRoomConnectionLifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,KAAK,CAAA;AAE5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AAEzE,MAAM,UAAU,0BAA0B,CAAC,MAAc,EAAE,KAA0B;IACnF,SAAS,gBAAgB;QACvB,MAAM,WAAW,GAAG,KAAK,EAAE,CAAA;QAE3B,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAM;QACR,CAAC;QAED,uBAAuB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IAC9C,CAAC;IAED,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;IAEF,WAAW,CAAC,GAAG,EAAE;QACf,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface RoomStateChangedEvent {
|
|
2
|
+
roomId: string;
|
|
3
|
+
stateVersion: number;
|
|
4
|
+
}
|
|
5
|
+
interface RoomChatMessageCreatedEvent {
|
|
6
|
+
roomId: string;
|
|
7
|
+
messageId: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function useRoomRealtime(roomId: string, handlers: {
|
|
10
|
+
onStateChanged?: (event: RoomStateChangedEvent) => void | Promise<void>;
|
|
11
|
+
onChatMessageCreated?: (event: RoomChatMessageCreatedEvent) => void | Promise<void>;
|
|
12
|
+
}): void;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=useRoomRealtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRoomRealtime.d.ts","sourceRoot":"","sources":["../../src/composables/useRoomRealtime.ts"],"names":[],"mappings":"AAIA,UAAU,qBAAqB;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,UAAU,2BAA2B;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE;IACR,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,2BAA2B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACpF,GACA,IAAI,CAcN"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { onBeforeUnmount } from 'vue';
|
|
2
|
+
import { roomRealtimeClient } from '../realtime/realtimeClient';
|
|
3
|
+
export function useRoomRealtime(roomId, handlers) {
|
|
4
|
+
const echo = roomRealtimeClient();
|
|
5
|
+
const channel = echo.channel(`room.${roomId}`);
|
|
6
|
+
channel.listen('.room.state.changed', (event) => {
|
|
7
|
+
void handlers.onStateChanged?.(event);
|
|
8
|
+
});
|
|
9
|
+
channel.listen('.room.chat.message.created', (event) => {
|
|
10
|
+
void handlers.onChatMessageCreated?.(event);
|
|
11
|
+
});
|
|
12
|
+
onBeforeUnmount(() => {
|
|
13
|
+
echo.leave(`room.${roomId}`);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=useRoomRealtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRoomRealtime.js","sourceRoot":"","sources":["../../src/composables/useRoomRealtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,KAAK,CAAA;AAErC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAY/D,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,QAGC;IAED,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAA;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,MAAM,EAAE,CAAC,CAAA;IAE9C,OAAO,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC,KAA4B,EAAE,EAAE;QACrE,KAAK,QAAQ,CAAC,cAAc,EAAE,CAAC,KAAK,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IACF,OAAO,CAAC,MAAM,CAAC,4BAA4B,EAAE,CAAC,KAAkC,EAAE,EAAE;QAClF,KAAK,QAAQ,CAAC,oBAAoB,EAAE,CAAC,KAAK,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,eAAe,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,KAAK,CAAC,QAAQ,MAAM,EAAE,CAAC,CAAA;IAC9B,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { useRoomConnectionLifecycle } from './composables/useRoomConnectionLifecycle';
|
|
2
|
+
export { useRoomRealtime } from './composables/useRoomRealtime';
|
|
3
|
+
export { configureTurnEngineRealtime } from './realtime/realtimeClient';
|
|
4
|
+
export { bearer, http } from './repositories/http';
|
|
5
|
+
export { createRoom, disconnectRoom, disconnectRoomKeepalive, getRoomState, joinRoom, leaveRoom, startRoomGame, } from './repositories/roomsRepository';
|
|
6
|
+
export { listChatMessages, sendChatMessage, type ChatMessageKind, } from './repositories/chatRepository';
|
|
7
|
+
export { useSessionStore } from './stores/sessionStore';
|
|
8
|
+
export type { ChatMessageView } from './types/chat';
|
|
9
|
+
export type { LobbyPlayer, RoomSessionResponse, RoomStateResponse, RoomSummary, } from './types/room';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAA;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAA;AACvE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EACL,UAAU,EACV,cAAc,EACd,uBAAuB,EACvB,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,aAAa,GACd,MAAM,gCAAgC,CAAA;AACvC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,KAAK,eAAe,GACrB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,YAAY,EACV,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,WAAW,GACZ,MAAM,cAAc,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { useRoomConnectionLifecycle } from './composables/useRoomConnectionLifecycle';
|
|
2
|
+
export { useRoomRealtime } from './composables/useRoomRealtime';
|
|
3
|
+
export { configureTurnEngineRealtime } from './realtime/realtimeClient';
|
|
4
|
+
export { bearer, http } from './repositories/http';
|
|
5
|
+
export { createRoom, disconnectRoom, disconnectRoomKeepalive, getRoomState, joinRoom, leaveRoom, startRoomGame, } from './repositories/roomsRepository';
|
|
6
|
+
export { listChatMessages, sendChatMessage, } from './repositories/chatRepository';
|
|
7
|
+
export { useSessionStore } from './stores/sessionStore';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAA;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAA;AACvE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EACL,UAAU,EACV,cAAc,EACd,uBAAuB,EACvB,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,aAAa,GACd,MAAM,gCAAgC,CAAA;AACvC,OAAO,EACL,gBAAgB,EAChB,eAAe,GAEhB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface RoomChannel {
|
|
2
|
+
listen(event: string, callback: (payload: never) => void): RoomChannel;
|
|
3
|
+
}
|
|
4
|
+
interface RealtimeClient {
|
|
5
|
+
channel(name: string): RoomChannel;
|
|
6
|
+
leave(name: string): void;
|
|
7
|
+
}
|
|
8
|
+
export declare function configureTurnEngineRealtime(client: RealtimeClient): void;
|
|
9
|
+
export declare function roomRealtimeClient(): RealtimeClient;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=realtimeClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtimeClient.d.ts","sourceRoot":"","sources":["../../src/realtime/realtimeClient.ts"],"names":[],"mappings":"AAAA,UAAU,WAAW;IACnB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,KAAK,KAAK,IAAI,GAAG,WAAW,CAAA;CACvE;AAED,UAAU,cAAc;IACtB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAClC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAID,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAExE;AAED,wBAAgB,kBAAkB,IAAI,cAAc,CAMnD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
let realtimeClient = null;
|
|
2
|
+
export function configureTurnEngineRealtime(client) {
|
|
3
|
+
realtimeClient = client;
|
|
4
|
+
}
|
|
5
|
+
export function roomRealtimeClient() {
|
|
6
|
+
if (!realtimeClient) {
|
|
7
|
+
throw new Error('Turn engine realtime client has not been configured.');
|
|
8
|
+
}
|
|
9
|
+
return realtimeClient;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=realtimeClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtimeClient.js","sourceRoot":"","sources":["../../src/realtime/realtimeClient.ts"],"names":[],"mappings":"AASA,IAAI,cAAc,GAA0B,IAAI,CAAA;AAEhD,MAAM,UAAU,2BAA2B,CAAC,MAAsB;IAChE,cAAc,GAAG,MAAM,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;IACzE,CAAC;IAED,OAAO,cAAc,CAAA;AACvB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ChatMessageView } from '../types/chat';
|
|
2
|
+
export type ChatMessageKind = ChatMessageView['kind'];
|
|
3
|
+
export declare function listChatMessages(roomId: string, token: string, kind?: ChatMessageKind): Promise<ChatMessageView[]>;
|
|
4
|
+
export declare function sendChatMessage(roomId: string, token: string, message: string): Promise<ChatMessageView>;
|
|
5
|
+
//# sourceMappingURL=chatRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatRepository.d.ts","sourceRoot":"","sources":["../../src/repositories/chatRepository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAEpD,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC,MAAM,CAAC,CAAA;AAErD,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,eAAwB,GAC7B,OAAO,CAAC,eAAe,EAAE,CAAC,CAO5B;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,CAAC,CAQ1B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { bearer, http } from './http';
|
|
2
|
+
export async function listChatMessages(roomId, token, kind = 'chat') {
|
|
3
|
+
const response = await http.get(`/rooms/${roomId}/chat/messages`, { headers: bearer(token), params: { kind } });
|
|
4
|
+
return response.data.messages;
|
|
5
|
+
}
|
|
6
|
+
export async function sendChatMessage(roomId, token, message) {
|
|
7
|
+
const response = await http.post(`/rooms/${roomId}/chat/messages`, { message }, { headers: bearer(token) });
|
|
8
|
+
return response.data.message;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=chatRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatRepository.js","sourceRoot":"","sources":["../../src/repositories/chatRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAKrC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,EACd,KAAa,EACb,OAAwB,MAAM;IAE9B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAC7B,UAAU,MAAM,gBAAgB,EAChC,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAC7C,CAAA;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAA;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,KAAa,EACb,OAAe;IAEf,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAC9B,UAAU,MAAM,gBAAgB,EAChC,EAAE,OAAO,EAAE,EACX,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAC3B,CAAA;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAA;AAC9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/repositories/http.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,IAAI,+BAKf,CAAA;AAEF,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,CAI/D"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
export const http = axios.create({
|
|
3
|
+
baseURL: '/api',
|
|
4
|
+
headers: {
|
|
5
|
+
Accept: 'application/json',
|
|
6
|
+
},
|
|
7
|
+
});
|
|
8
|
+
export function bearer(token) {
|
|
9
|
+
return {
|
|
10
|
+
Authorization: `Bearer ${token}`,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/repositories/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,CAAC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;IAC/B,OAAO,EAAE,MAAM;IACf,OAAO,EAAE;QACP,MAAM,EAAE,kBAAkB;KAC3B;CACF,CAAC,CAAA;AAEF,MAAM,UAAU,MAAM,CAAC,KAAa;IAClC,OAAO;QACL,aAAa,EAAE,UAAU,KAAK,EAAE;KACjC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RoomSessionResponse, RoomStateResponse } from '../types/room';
|
|
2
|
+
export declare function createRoom(nickname: string): Promise<RoomSessionResponse>;
|
|
3
|
+
export declare function joinRoom(roomId: string, nickname: string): Promise<RoomSessionResponse>;
|
|
4
|
+
export declare function getRoomState<TState = unknown>(roomId: string, token: string): Promise<RoomStateResponse<TState>>;
|
|
5
|
+
export declare function startRoomGame(roomId: string, token: string): Promise<unknown>;
|
|
6
|
+
export declare function leaveRoom(roomId: string, token: string): Promise<unknown>;
|
|
7
|
+
export declare function disconnectRoom(roomId: string, token: string): Promise<unknown>;
|
|
8
|
+
export declare function disconnectRoomKeepalive(roomId: string, token: string): void;
|
|
9
|
+
//# sourceMappingURL=roomsRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roomsRepository.d.ts","sourceRoot":"","sources":["../../src/repositories/roomsRepository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAE3E,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAI/E;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAI7F;AAED,wBAAsB,YAAY,CAAC,MAAM,GAAG,OAAO,EACjD,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAMpC;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnF;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAM/E;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMpF;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAS3E"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { bearer, http } from './http';
|
|
2
|
+
export async function createRoom(nickname) {
|
|
3
|
+
const response = await http.post('/rooms', { nickname });
|
|
4
|
+
return response.data;
|
|
5
|
+
}
|
|
6
|
+
export async function joinRoom(roomId, nickname) {
|
|
7
|
+
const response = await http.post(`/rooms/${roomId}/join`, { nickname });
|
|
8
|
+
return response.data;
|
|
9
|
+
}
|
|
10
|
+
export async function getRoomState(roomId, token) {
|
|
11
|
+
const response = await http.get(`/rooms/${roomId}/state`, {
|
|
12
|
+
headers: bearer(token),
|
|
13
|
+
});
|
|
14
|
+
return response.data;
|
|
15
|
+
}
|
|
16
|
+
export async function startRoomGame(roomId, token) {
|
|
17
|
+
const response = await http.post(`/rooms/${roomId}/start`, {}, {
|
|
18
|
+
headers: bearer(token),
|
|
19
|
+
});
|
|
20
|
+
return response.data;
|
|
21
|
+
}
|
|
22
|
+
export async function leaveRoom(roomId, token) {
|
|
23
|
+
const response = await http.post(`/rooms/${roomId}/leave`, {}, {
|
|
24
|
+
headers: bearer(token),
|
|
25
|
+
});
|
|
26
|
+
return response.data;
|
|
27
|
+
}
|
|
28
|
+
export async function disconnectRoom(roomId, token) {
|
|
29
|
+
const response = await http.post(`/rooms/${roomId}/disconnect`, {}, {
|
|
30
|
+
headers: bearer(token),
|
|
31
|
+
});
|
|
32
|
+
return response.data;
|
|
33
|
+
}
|
|
34
|
+
export function disconnectRoomKeepalive(roomId, token) {
|
|
35
|
+
void fetch(`/api/rooms/${roomId}/disconnect`, {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
headers: {
|
|
38
|
+
Accept: 'application/json',
|
|
39
|
+
Authorization: `Bearer ${token}`,
|
|
40
|
+
},
|
|
41
|
+
keepalive: true,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=roomsRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roomsRepository.js","sourceRoot":"","sources":["../../src/repositories/roomsRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAGrC,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB;IAC/C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAsB,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAA;IAE7E,OAAO,QAAQ,CAAC,IAAI,CAAA;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc,EAAE,QAAgB;IAC7D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAsB,UAAU,MAAM,OAAO,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAA;IAE5F,OAAO,QAAQ,CAAC,IAAI,CAAA;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAc,EACd,KAAa;IAEb,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAA4B,UAAU,MAAM,QAAQ,EAAE;QACnF,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;KACvB,CAAC,CAAA;IAEF,OAAO,QAAQ,CAAC,IAAI,CAAA;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc,EAAE,KAAa;IAC/D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAU,UAAU,MAAM,QAAQ,EAAE,EAAE,EAAE;QACtE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;KACvB,CAAC,CAAA;IAEF,OAAO,QAAQ,CAAC,IAAI,CAAA;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAc,EAAE,KAAa;IAC3D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAU,UAAU,MAAM,QAAQ,EAAE,EAAE,EAAE;QACtE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;KACvB,CAAC,CAAA;IAEF,OAAO,QAAQ,CAAC,IAAI,CAAA;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc,EAAE,KAAa;IAChE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAU,UAAU,MAAM,aAAa,EAAE,EAAE,EAAE;QAC3E,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;KACvB,CAAC,CAAA;IAEF,OAAO,QAAQ,CAAC,IAAI,CAAA;AACtB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAAc,EAAE,KAAa;IACnE,KAAK,KAAK,CAAC,cAAc,MAAM,aAAa,EAAE;QAC5C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,MAAM,EAAE,kBAAkB;YAC1B,aAAa,EAAE,UAAU,KAAK,EAAE;SACjC;QACD,SAAS,EAAE,IAAI;KAChB,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RoomSessionResponse } from '../types/room';
|
|
2
|
+
interface SessionState {
|
|
3
|
+
roomId: string | null;
|
|
4
|
+
playerId: string | null;
|
|
5
|
+
playerToken: string | null;
|
|
6
|
+
publicInviteUrl: string | null;
|
|
7
|
+
privateReconnectUrl: string | null;
|
|
8
|
+
}
|
|
9
|
+
type StoredSessions = Record<string, SessionState>;
|
|
10
|
+
export declare const useSessionStore: import("pinia").StoreDefinition<"session", SessionState, {
|
|
11
|
+
hasSession: (state: {
|
|
12
|
+
roomId: string | null;
|
|
13
|
+
playerId: string | null;
|
|
14
|
+
playerToken: string | null;
|
|
15
|
+
publicInviteUrl: string | null;
|
|
16
|
+
privateReconnectUrl: string | null;
|
|
17
|
+
} & import("pinia").PiniaCustomStateProperties<SessionState>) => boolean;
|
|
18
|
+
}, {
|
|
19
|
+
restore(roomId: string): void;
|
|
20
|
+
save(session: RoomSessionResponse): void;
|
|
21
|
+
saveManual(session: SessionState): void;
|
|
22
|
+
clear(roomId?: string | null): void;
|
|
23
|
+
persistSession(session: SessionState): void;
|
|
24
|
+
storedSessions(): StoredSessions;
|
|
25
|
+
parseStoredSessions(): StoredSessions;
|
|
26
|
+
}>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=sessionStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionStore.d.ts","sourceRoot":"","sources":["../../src/stores/sessionStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAIxD,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAA;CACnC;AAED,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;AAElD,eAAO,MAAM,eAAe;;gBATlB,MAAM,GAAG,IAAI;kBACX,MAAM,GAAG,IAAI;qBACV,MAAM,GAAG,IAAI;yBACT,MAAM,GAAG,IAAI;6BACT,MAAM,GAAG,IAAI;qEAcX,OAAO;;oBAGZ,MAAM,GAAG,IAAI;kBASf,mBAAmB,GAAG,IAAI;wBAWpB,YAAY,GAAG,IAAI;mBAGxB,MAAM,GAAG,IAAI,GAAG,IAAI;4BAcX,YAAY,GAAG,IAAI;sBAUzB,cAAc;2BAGT,cAAc;EAcvC,CAAA"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
const STORAGE_KEY = 'turn-engine.sessions';
|
|
3
|
+
export const useSessionStore = defineStore('session', {
|
|
4
|
+
state: () => ({
|
|
5
|
+
roomId: null,
|
|
6
|
+
playerId: null,
|
|
7
|
+
playerToken: null,
|
|
8
|
+
publicInviteUrl: null,
|
|
9
|
+
privateReconnectUrl: null,
|
|
10
|
+
}),
|
|
11
|
+
getters: {
|
|
12
|
+
hasSession: (state) => Boolean(state.roomId && state.playerId && state.playerToken),
|
|
13
|
+
},
|
|
14
|
+
actions: {
|
|
15
|
+
restore(roomId) {
|
|
16
|
+
const session = this.storedSessions()[roomId];
|
|
17
|
+
if (!session) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
this.$patch(session);
|
|
21
|
+
},
|
|
22
|
+
save(session) {
|
|
23
|
+
const state = {
|
|
24
|
+
roomId: session.roomId,
|
|
25
|
+
playerId: session.playerId,
|
|
26
|
+
playerToken: session.playerToken,
|
|
27
|
+
publicInviteUrl: session.publicInviteUrl,
|
|
28
|
+
privateReconnectUrl: session.privateReconnectUrl,
|
|
29
|
+
};
|
|
30
|
+
this.persistSession(state);
|
|
31
|
+
},
|
|
32
|
+
saveManual(session) {
|
|
33
|
+
this.persistSession(session);
|
|
34
|
+
},
|
|
35
|
+
clear(roomId) {
|
|
36
|
+
const targetRoomId = roomId ?? this.roomId;
|
|
37
|
+
if (targetRoomId) {
|
|
38
|
+
const sessions = this.storedSessions();
|
|
39
|
+
delete sessions[targetRoomId];
|
|
40
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(sessions));
|
|
41
|
+
}
|
|
42
|
+
if (!targetRoomId || this.roomId === targetRoomId) {
|
|
43
|
+
this.$reset();
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
persistSession(session) {
|
|
47
|
+
if (!session.roomId) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const sessions = this.storedSessions();
|
|
51
|
+
sessions[session.roomId] = session;
|
|
52
|
+
this.$patch(session);
|
|
53
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(sessions));
|
|
54
|
+
},
|
|
55
|
+
storedSessions() {
|
|
56
|
+
return this.parseStoredSessions();
|
|
57
|
+
},
|
|
58
|
+
parseStoredSessions() {
|
|
59
|
+
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
60
|
+
if (!raw) {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(raw);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=sessionStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionStore.js","sourceRoot":"","sources":["../../src/stores/sessionStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/types/chat.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,GAAG,UAAU,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/types/chat.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface RoomSessionResponse {
|
|
2
|
+
roomId: string;
|
|
3
|
+
roomStatus: string;
|
|
4
|
+
playerId: string;
|
|
5
|
+
playerToken: string;
|
|
6
|
+
publicInviteUrl: string;
|
|
7
|
+
privateReconnectUrl: string;
|
|
8
|
+
recovered?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface RoomSummary {
|
|
11
|
+
id: string;
|
|
12
|
+
status: string;
|
|
13
|
+
hostPlayerId: string;
|
|
14
|
+
rulesetVersion: string;
|
|
15
|
+
}
|
|
16
|
+
export interface LobbyPlayer {
|
|
17
|
+
id: string;
|
|
18
|
+
nickname: string;
|
|
19
|
+
is_host: boolean;
|
|
20
|
+
turn_order_index: number | null;
|
|
21
|
+
connected: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface RoomStateResponse<TState = unknown> {
|
|
24
|
+
room: RoomSummary;
|
|
25
|
+
players: LobbyPlayer[];
|
|
26
|
+
state: TState | null;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=room.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../../src/types/room.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,iBAAiB,CAAC,MAAM,GAAG,OAAO;IACjD,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room.js","sourceRoot":"","sources":["../../src/types/room.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@javleds/vue-game-engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Reusable Vue client utilities for online turn-based board games.",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"vue",
|
|
10
|
+
"board-game",
|
|
11
|
+
"turn-based",
|
|
12
|
+
"game-engine",
|
|
13
|
+
"realtime"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/javleds/vue-game-engine#readme",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/javleds/vue-game-engine.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/javleds/vue-game-engine/issues"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md",
|
|
26
|
+
"README.es.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"module": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc -p tsconfig.json",
|
|
40
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
41
|
+
"prepack": "npm run build"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"axios": "^1.7.9",
|
|
45
|
+
"laravel-echo": "^2.0.2",
|
|
46
|
+
"pinia": "^2.3.0",
|
|
47
|
+
"vue": "^3.5.13"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"axios": "^1.7.9",
|
|
51
|
+
"laravel-echo": "^2.0.2",
|
|
52
|
+
"pinia": "^2.3.0",
|
|
53
|
+
"typescript": "^5.7.2",
|
|
54
|
+
"vue": "^3.5.13"
|
|
55
|
+
}
|
|
56
|
+
}
|