@beta-gamer/angular 0.1.1 → 0.1.3
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 +185 -0
- package/dist/index.d.mts +125 -24
- package/dist/index.d.ts +125 -24
- package/dist/index.js +156 -85
- package/dist/index.mjs +155 -84
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -13,9 +13,8 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
13
13
|
import { Injectable, signal } from "@angular/core";
|
|
14
14
|
import { io } from "socket.io-client";
|
|
15
15
|
function decodeToken(token) {
|
|
16
|
-
if (!token || typeof token !== "string")
|
|
16
|
+
if (!token || typeof token !== "string")
|
|
17
17
|
throw new Error("@beta-gamer/angular: token is required and must be a string");
|
|
18
|
-
}
|
|
19
18
|
const parts = token.split(".");
|
|
20
19
|
if (parts.length < 2) throw new Error("@beta-gamer/angular: invalid session token format");
|
|
21
20
|
const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -26,20 +25,33 @@ var BetaGamerService = class {
|
|
|
26
25
|
constructor() {
|
|
27
26
|
this._socket = null;
|
|
28
27
|
this._token = "";
|
|
28
|
+
/** Decoded session token payload — null until `init()` is called */
|
|
29
29
|
this.session = signal(null);
|
|
30
|
+
/** Live game state updated by server events */
|
|
30
31
|
this.gameState = signal({ status: "pending", players: [] });
|
|
31
32
|
}
|
|
32
33
|
get token() {
|
|
33
34
|
return this._token;
|
|
34
35
|
}
|
|
36
|
+
/** The active socket.io connection — available after `init()` with `connectSocket=true` */
|
|
35
37
|
get socket() {
|
|
36
38
|
return this._socket;
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
/**
|
|
41
|
+
* @description Initialises the service with a session token.
|
|
42
|
+
* Decodes the token, sets up reactive state, and optionally connects the socket.
|
|
43
|
+
*
|
|
44
|
+
* @param token - JWT session token from your backend
|
|
45
|
+
* @param serverUrl - Base URL of the Beta Gamer server
|
|
46
|
+
* @param socketPath - socket.io path (default `/socket.io`)
|
|
47
|
+
* @param connectSocket - Set false to skip socket connection (e.g. for SSR or testing)
|
|
48
|
+
*/
|
|
49
|
+
init(token, serverUrl = "https://api.beta-gamer.com", socketPath = "/socket.io", connectSocket = true) {
|
|
39
50
|
this._token = token;
|
|
40
51
|
const payload = decodeToken(token);
|
|
41
52
|
this.session.set(payload);
|
|
42
53
|
this.gameState.set({ status: "pending", players: payload.players });
|
|
54
|
+
if (!connectSocket) return;
|
|
43
55
|
const s = io(`${serverUrl}/${payload.game}`, {
|
|
44
56
|
auth: { token },
|
|
45
57
|
path: socketPath,
|
|
@@ -114,7 +126,7 @@ var TimerComponent = class {
|
|
|
114
126
|
constructor() {
|
|
115
127
|
this.player = "self";
|
|
116
128
|
this.initialSeconds = 600;
|
|
117
|
-
this.seconds =
|
|
129
|
+
this.seconds = 600;
|
|
118
130
|
this.interval = null;
|
|
119
131
|
this.svc = inject2(BetaGamerService);
|
|
120
132
|
}
|
|
@@ -125,20 +137,17 @@ var TimerComponent = class {
|
|
|
125
137
|
}
|
|
126
138
|
ngOnInit() {
|
|
127
139
|
this.seconds = this.initialSeconds;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (clocks[this.player] !== void 0) this.seconds = clocks[this.player];
|
|
132
|
-
});
|
|
133
|
-
}
|
|
140
|
+
this.svc.socket?.on("game:clock", (clocks) => {
|
|
141
|
+
if (clocks[this.player] !== void 0) this.seconds = clocks[this.player];
|
|
142
|
+
});
|
|
134
143
|
this.interval = setInterval(() => {
|
|
135
|
-
if (this.svc.gameState().status === "active")
|
|
144
|
+
if (this.svc.gameState().status === "active")
|
|
136
145
|
this.seconds = Math.max(0, this.seconds - 1);
|
|
137
|
-
}
|
|
138
146
|
}, 1e3);
|
|
139
147
|
}
|
|
140
148
|
ngOnDestroy() {
|
|
141
149
|
if (this.interval) clearInterval(this.interval);
|
|
150
|
+
this.svc.socket?.off("game:clock");
|
|
142
151
|
}
|
|
143
152
|
};
|
|
144
153
|
__decorateClass([
|
|
@@ -159,30 +168,91 @@ TimerComponent = __decorateClass([
|
|
|
159
168
|
})
|
|
160
169
|
], TimerComponent);
|
|
161
170
|
|
|
162
|
-
// src/components/chess/
|
|
163
|
-
import { Component as Component3, Input as
|
|
164
|
-
|
|
171
|
+
// src/components/chess/ChessBoardComponent.ts
|
|
172
|
+
import { Component as Component3, Input as Input4 } from "@angular/core";
|
|
173
|
+
|
|
174
|
+
// src/components/shared/EmbedBoardBase.ts
|
|
175
|
+
import { Directive, Input as Input3, Output, EventEmitter, ViewChild, inject as inject3 } from "@angular/core";
|
|
176
|
+
var EmbedBoardBase = class {
|
|
165
177
|
constructor() {
|
|
166
178
|
this.serverUrl = "https://api.beta-gamer.com";
|
|
179
|
+
this.onLeave = new EventEmitter();
|
|
167
180
|
this.svc = inject3(BetaGamerService);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
181
|
+
this.messageHandler = (e) => {
|
|
182
|
+
try {
|
|
183
|
+
const data = typeof e.data === "string" ? JSON.parse(e.data) : e.data;
|
|
184
|
+
if (data?.type === "bg:leave") this.onLeave.emit();
|
|
185
|
+
} catch {
|
|
186
|
+
}
|
|
187
|
+
};
|
|
171
188
|
}
|
|
172
189
|
ngAfterViewInit() {
|
|
190
|
+
window.addEventListener("message", this.messageHandler);
|
|
173
191
|
const iframe = this.iframeRef?.nativeElement;
|
|
174
192
|
if (!iframe) return;
|
|
175
193
|
iframe.addEventListener("load", () => {
|
|
176
194
|
iframe.contentWindow?.postMessage({ type: "bg:init", token: this.svc.token }, "*");
|
|
177
195
|
});
|
|
178
196
|
}
|
|
197
|
+
ngOnDestroy() {
|
|
198
|
+
window.removeEventListener("message", this.messageHandler);
|
|
199
|
+
}
|
|
200
|
+
/** Builds a query string from a params object, omitting undefined values */
|
|
201
|
+
buildQuery(params) {
|
|
202
|
+
const p = new URLSearchParams();
|
|
203
|
+
for (const [k, v] of Object.entries(params)) if (v !== void 0) p.set(k, v);
|
|
204
|
+
const qs = p.toString();
|
|
205
|
+
return qs ? "?" + qs : "";
|
|
206
|
+
}
|
|
179
207
|
};
|
|
180
208
|
__decorateClass([
|
|
181
209
|
Input3()
|
|
182
|
-
],
|
|
210
|
+
], EmbedBoardBase.prototype, "serverUrl", 2);
|
|
211
|
+
__decorateClass([
|
|
212
|
+
Output()
|
|
213
|
+
], EmbedBoardBase.prototype, "onLeave", 2);
|
|
183
214
|
__decorateClass([
|
|
184
215
|
ViewChild("iframe")
|
|
185
|
-
],
|
|
216
|
+
], EmbedBoardBase.prototype, "iframeRef", 2);
|
|
217
|
+
EmbedBoardBase = __decorateClass([
|
|
218
|
+
Directive()
|
|
219
|
+
], EmbedBoardBase);
|
|
220
|
+
|
|
221
|
+
// src/components/chess/ChessBoardComponent.ts
|
|
222
|
+
var ChessBoardComponent = class extends EmbedBoardBase {
|
|
223
|
+
constructor() {
|
|
224
|
+
super(...arguments);
|
|
225
|
+
this.showAfkWarning = true;
|
|
226
|
+
this.showCoords = true;
|
|
227
|
+
this.showLastMove = true;
|
|
228
|
+
this.showLegalMoves = true;
|
|
229
|
+
this.orientation = "auto";
|
|
230
|
+
}
|
|
231
|
+
get embedUrl() {
|
|
232
|
+
return this.serverUrl + "/embed/chess" + this.buildQuery({
|
|
233
|
+
afkWarning: !this.showAfkWarning ? "0" : void 0,
|
|
234
|
+
showCoords: !this.showCoords ? "0" : void 0,
|
|
235
|
+
showLastMove: !this.showLastMove ? "0" : void 0,
|
|
236
|
+
showLegalMoves: !this.showLegalMoves ? "0" : void 0,
|
|
237
|
+
orientation: this.orientation !== "auto" ? this.orientation : void 0
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
__decorateClass([
|
|
242
|
+
Input4()
|
|
243
|
+
], ChessBoardComponent.prototype, "showAfkWarning", 2);
|
|
244
|
+
__decorateClass([
|
|
245
|
+
Input4()
|
|
246
|
+
], ChessBoardComponent.prototype, "showCoords", 2);
|
|
247
|
+
__decorateClass([
|
|
248
|
+
Input4()
|
|
249
|
+
], ChessBoardComponent.prototype, "showLastMove", 2);
|
|
250
|
+
__decorateClass([
|
|
251
|
+
Input4()
|
|
252
|
+
], ChessBoardComponent.prototype, "showLegalMoves", 2);
|
|
253
|
+
__decorateClass([
|
|
254
|
+
Input4()
|
|
255
|
+
], ChessBoardComponent.prototype, "orientation", 2);
|
|
186
256
|
ChessBoardComponent = __decorateClass([
|
|
187
257
|
Component3({
|
|
188
258
|
selector: "bg-chess-board",
|
|
@@ -194,19 +264,25 @@ ChessBoardComponent = __decorateClass([
|
|
|
194
264
|
`
|
|
195
265
|
})
|
|
196
266
|
], ChessBoardComponent);
|
|
267
|
+
|
|
268
|
+
// src/components/chess/ChessMoveHistoryComponent.ts
|
|
269
|
+
import { Component as Component4 } from "@angular/core";
|
|
197
270
|
var ChessMoveHistoryComponent = class {
|
|
198
271
|
};
|
|
199
272
|
ChessMoveHistoryComponent = __decorateClass([
|
|
200
|
-
|
|
273
|
+
Component4({
|
|
201
274
|
selector: "bg-chess-move-history",
|
|
202
275
|
standalone: true,
|
|
203
276
|
template: `<div data-role="move-history"></div>`
|
|
204
277
|
})
|
|
205
278
|
], ChessMoveHistoryComponent);
|
|
279
|
+
|
|
280
|
+
// src/components/chess/ChessCapturedPiecesComponent.ts
|
|
281
|
+
import { Component as Component5 } from "@angular/core";
|
|
206
282
|
var ChessCapturedPiecesComponent = class {
|
|
207
283
|
};
|
|
208
284
|
ChessCapturedPiecesComponent = __decorateClass([
|
|
209
|
-
|
|
285
|
+
Component5({
|
|
210
286
|
selector: "bg-chess-captured-pieces",
|
|
211
287
|
standalone: true,
|
|
212
288
|
template: `<div data-role="captured-pieces"></div>`
|
|
@@ -214,31 +290,33 @@ ChessCapturedPiecesComponent = __decorateClass([
|
|
|
214
290
|
], ChessCapturedPiecesComponent);
|
|
215
291
|
|
|
216
292
|
// src/components/checkers/index.ts
|
|
217
|
-
import { Component as
|
|
218
|
-
var CheckersBoardComponent = class {
|
|
293
|
+
import { Component as Component6, Input as Input5 } from "@angular/core";
|
|
294
|
+
var CheckersBoardComponent = class extends EmbedBoardBase {
|
|
219
295
|
constructor() {
|
|
220
|
-
|
|
221
|
-
this.
|
|
296
|
+
super(...arguments);
|
|
297
|
+
this.showAfkWarning = true;
|
|
298
|
+
this.showLastMove = true;
|
|
299
|
+
this.orientation = "auto";
|
|
222
300
|
}
|
|
223
301
|
get embedUrl() {
|
|
224
|
-
return
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (!iframe) return;
|
|
229
|
-
iframe.addEventListener("load", () => {
|
|
230
|
-
iframe.contentWindow?.postMessage({ type: "bg:init", token: this.svc.token }, "*");
|
|
302
|
+
return this.serverUrl + "/embed/checkers" + this.buildQuery({
|
|
303
|
+
afkWarning: !this.showAfkWarning ? "0" : void 0,
|
|
304
|
+
showLastMove: !this.showLastMove ? "0" : void 0,
|
|
305
|
+
orientation: this.orientation !== "auto" ? this.orientation : void 0
|
|
231
306
|
});
|
|
232
307
|
}
|
|
233
308
|
};
|
|
234
309
|
__decorateClass([
|
|
235
|
-
|
|
236
|
-
], CheckersBoardComponent.prototype, "
|
|
310
|
+
Input5()
|
|
311
|
+
], CheckersBoardComponent.prototype, "showAfkWarning", 2);
|
|
237
312
|
__decorateClass([
|
|
238
|
-
|
|
239
|
-
], CheckersBoardComponent.prototype, "
|
|
313
|
+
Input5()
|
|
314
|
+
], CheckersBoardComponent.prototype, "showLastMove", 2);
|
|
315
|
+
__decorateClass([
|
|
316
|
+
Input5()
|
|
317
|
+
], CheckersBoardComponent.prototype, "orientation", 2);
|
|
240
318
|
CheckersBoardComponent = __decorateClass([
|
|
241
|
-
|
|
319
|
+
Component6({
|
|
242
320
|
selector: "bg-checkers-board",
|
|
243
321
|
standalone: true,
|
|
244
322
|
template: `
|
|
@@ -249,32 +327,24 @@ CheckersBoardComponent = __decorateClass([
|
|
|
249
327
|
})
|
|
250
328
|
], CheckersBoardComponent);
|
|
251
329
|
|
|
252
|
-
// src/components/connect4/
|
|
253
|
-
import { Component as
|
|
254
|
-
var Connect4BoardComponent = class {
|
|
330
|
+
// src/components/connect4/Connect4BoardComponent.ts
|
|
331
|
+
import { Component as Component7, Input as Input6 } from "@angular/core";
|
|
332
|
+
var Connect4BoardComponent = class extends EmbedBoardBase {
|
|
255
333
|
constructor() {
|
|
256
|
-
|
|
257
|
-
this.
|
|
334
|
+
super(...arguments);
|
|
335
|
+
this.showAfkWarning = true;
|
|
258
336
|
}
|
|
259
337
|
get embedUrl() {
|
|
260
|
-
return
|
|
261
|
-
|
|
262
|
-
ngAfterViewInit() {
|
|
263
|
-
const iframe = this.iframeRef?.nativeElement;
|
|
264
|
-
if (!iframe) return;
|
|
265
|
-
iframe.addEventListener("load", () => {
|
|
266
|
-
iframe.contentWindow?.postMessage({ type: "bg:init", token: this.svc.token }, "*");
|
|
338
|
+
return this.serverUrl + "/embed/connect4" + this.buildQuery({
|
|
339
|
+
afkWarning: !this.showAfkWarning ? "0" : void 0
|
|
267
340
|
});
|
|
268
341
|
}
|
|
269
342
|
};
|
|
270
343
|
__decorateClass([
|
|
271
|
-
|
|
272
|
-
], Connect4BoardComponent.prototype, "
|
|
273
|
-
__decorateClass([
|
|
274
|
-
ViewChild3("iframe")
|
|
275
|
-
], Connect4BoardComponent.prototype, "iframeRef", 2);
|
|
344
|
+
Input6()
|
|
345
|
+
], Connect4BoardComponent.prototype, "showAfkWarning", 2);
|
|
276
346
|
Connect4BoardComponent = __decorateClass([
|
|
277
|
-
|
|
347
|
+
Component7({
|
|
278
348
|
selector: "bg-connect4-board",
|
|
279
349
|
standalone: true,
|
|
280
350
|
template: `
|
|
@@ -284,9 +354,12 @@ Connect4BoardComponent = __decorateClass([
|
|
|
284
354
|
`
|
|
285
355
|
})
|
|
286
356
|
], Connect4BoardComponent);
|
|
357
|
+
|
|
358
|
+
// src/components/connect4/Connect4ScoreComponent.ts
|
|
359
|
+
import { Component as Component8, inject as inject4 } from "@angular/core";
|
|
287
360
|
var Connect4ScoreComponent = class {
|
|
288
361
|
constructor() {
|
|
289
|
-
this.svc =
|
|
362
|
+
this.svc = inject4(BetaGamerService);
|
|
290
363
|
}
|
|
291
364
|
get scores() {
|
|
292
365
|
const s = this.svc.gameState()?.scores ?? {};
|
|
@@ -294,7 +367,7 @@ var Connect4ScoreComponent = class {
|
|
|
294
367
|
}
|
|
295
368
|
};
|
|
296
369
|
Connect4ScoreComponent = __decorateClass([
|
|
297
|
-
|
|
370
|
+
Component8({
|
|
298
371
|
selector: "bg-connect4-score",
|
|
299
372
|
standalone: true,
|
|
300
373
|
template: `
|
|
@@ -308,31 +381,23 @@ Connect4ScoreComponent = __decorateClass([
|
|
|
308
381
|
], Connect4ScoreComponent);
|
|
309
382
|
|
|
310
383
|
// src/components/tictactoe/index.ts
|
|
311
|
-
import { Component as
|
|
312
|
-
var TictactoeBoardComponent = class {
|
|
384
|
+
import { Component as Component9, Input as Input7 } from "@angular/core";
|
|
385
|
+
var TictactoeBoardComponent = class extends EmbedBoardBase {
|
|
313
386
|
constructor() {
|
|
314
|
-
|
|
315
|
-
this.
|
|
387
|
+
super(...arguments);
|
|
388
|
+
this.showAfkWarning = true;
|
|
316
389
|
}
|
|
317
390
|
get embedUrl() {
|
|
318
|
-
return
|
|
319
|
-
|
|
320
|
-
ngAfterViewInit() {
|
|
321
|
-
const iframe = this.iframeRef?.nativeElement;
|
|
322
|
-
if (!iframe) return;
|
|
323
|
-
iframe.addEventListener("load", () => {
|
|
324
|
-
iframe.contentWindow?.postMessage({ type: "bg:init", token: this.svc.token }, "*");
|
|
391
|
+
return this.serverUrl + "/embed/tictactoe" + this.buildQuery({
|
|
392
|
+
afkWarning: !this.showAfkWarning ? "0" : void 0
|
|
325
393
|
});
|
|
326
394
|
}
|
|
327
395
|
};
|
|
328
396
|
__decorateClass([
|
|
329
|
-
|
|
330
|
-
], TictactoeBoardComponent.prototype, "
|
|
331
|
-
__decorateClass([
|
|
332
|
-
ViewChild4("iframe")
|
|
333
|
-
], TictactoeBoardComponent.prototype, "iframeRef", 2);
|
|
397
|
+
Input7()
|
|
398
|
+
], TictactoeBoardComponent.prototype, "showAfkWarning", 2);
|
|
334
399
|
TictactoeBoardComponent = __decorateClass([
|
|
335
|
-
|
|
400
|
+
Component9({
|
|
336
401
|
selector: "bg-tictactoe-board",
|
|
337
402
|
standalone: true,
|
|
338
403
|
template: `
|
|
@@ -343,12 +408,12 @@ TictactoeBoardComponent = __decorateClass([
|
|
|
343
408
|
})
|
|
344
409
|
], TictactoeBoardComponent);
|
|
345
410
|
|
|
346
|
-
// src/components/subway-runner/
|
|
347
|
-
import { Component as
|
|
411
|
+
// src/components/subway-runner/SubwayRunnerGameComponent.ts
|
|
412
|
+
import { Component as Component10, Input as Input8, ViewChild as ViewChild2, inject as inject5 } from "@angular/core";
|
|
348
413
|
var SubwayRunnerGameComponent = class {
|
|
349
414
|
constructor() {
|
|
350
415
|
this.serverUrl = "https://api.beta-gamer.com";
|
|
351
|
-
this.svc =
|
|
416
|
+
this.svc = inject5(BetaGamerService);
|
|
352
417
|
}
|
|
353
418
|
get embedUrl() {
|
|
354
419
|
return `${this.serverUrl}/embed/subway-runner`;
|
|
@@ -362,13 +427,13 @@ var SubwayRunnerGameComponent = class {
|
|
|
362
427
|
}
|
|
363
428
|
};
|
|
364
429
|
__decorateClass([
|
|
365
|
-
|
|
430
|
+
Input8()
|
|
366
431
|
], SubwayRunnerGameComponent.prototype, "serverUrl", 2);
|
|
367
432
|
__decorateClass([
|
|
368
|
-
|
|
433
|
+
ViewChild2("iframe")
|
|
369
434
|
], SubwayRunnerGameComponent.prototype, "iframeRef", 2);
|
|
370
435
|
SubwayRunnerGameComponent = __decorateClass([
|
|
371
|
-
|
|
436
|
+
Component10({
|
|
372
437
|
selector: "bg-subway-runner",
|
|
373
438
|
standalone: true,
|
|
374
439
|
template: `
|
|
@@ -378,21 +443,27 @@ SubwayRunnerGameComponent = __decorateClass([
|
|
|
378
443
|
`
|
|
379
444
|
})
|
|
380
445
|
], SubwayRunnerGameComponent);
|
|
446
|
+
|
|
447
|
+
// src/components/subway-runner/SubwayRunnerScoreComponent.ts
|
|
448
|
+
import { Component as Component11, inject as inject6 } from "@angular/core";
|
|
381
449
|
var SubwayRunnerScoreComponent = class {
|
|
382
450
|
constructor() {
|
|
383
|
-
this.svc =
|
|
451
|
+
this.svc = inject6(BetaGamerService);
|
|
384
452
|
}
|
|
385
453
|
get score() {
|
|
386
454
|
return this.svc.gameState()?.score ?? 0;
|
|
387
455
|
}
|
|
388
456
|
};
|
|
389
457
|
SubwayRunnerScoreComponent = __decorateClass([
|
|
390
|
-
|
|
458
|
+
Component11({
|
|
391
459
|
selector: "bg-subway-runner-score",
|
|
392
460
|
standalone: true,
|
|
393
461
|
template: `<div data-role="score"><span data-role="score-value">{{ score }}</span></div>`
|
|
394
462
|
})
|
|
395
463
|
], SubwayRunnerScoreComponent);
|
|
464
|
+
|
|
465
|
+
// src/components/subway-runner/SubwayRunnerLivesComponent.ts
|
|
466
|
+
import { Component as Component12, inject as inject7 } from "@angular/core";
|
|
396
467
|
var SubwayRunnerLivesComponent = class {
|
|
397
468
|
constructor() {
|
|
398
469
|
this.svc = inject7(BetaGamerService);
|
|
@@ -402,7 +473,7 @@ var SubwayRunnerLivesComponent = class {
|
|
|
402
473
|
}
|
|
403
474
|
};
|
|
404
475
|
SubwayRunnerLivesComponent = __decorateClass([
|
|
405
|
-
|
|
476
|
+
Component12({
|
|
406
477
|
selector: "bg-subway-runner-lives",
|
|
407
478
|
standalone: true,
|
|
408
479
|
template: `<div data-role="lives"><span data-role="lives-value">{{ lives }}</span></div>`
|