keeperboard 2.0.1 → 2.0.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 +14 -2
- package/dist/index.d.mts +35 -13
- package/dist/index.d.ts +35 -13
- package/dist/index.js +251 -9
- package/dist/index.mjs +250 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,7 +52,6 @@ Most browser games should use `KeeperBoardSession`. Use `KeeperBoardClient` for
|
|
|
52
52
|
const session = new KeeperBoardSession({
|
|
53
53
|
apiKey: 'kb_dev_xxx', // Required
|
|
54
54
|
leaderboard: 'main', // Required - session is bound to one board
|
|
55
|
-
defaultPlayerName: 'ANON', // Optional (default: 'ANON')
|
|
56
55
|
identity: { keyPrefix: 'app_' }, // Optional localStorage prefix
|
|
57
56
|
cache: { ttlMs: 30000 }, // Optional TTL cache for getSnapshot()
|
|
58
57
|
retry: { maxAgeMs: 86400000 }, // Optional retry queue for failed submissions
|
|
@@ -61,10 +60,13 @@ const session = new KeeperBoardSession({
|
|
|
61
60
|
|
|
62
61
|
### Identity (auto-managed)
|
|
63
62
|
|
|
63
|
+
Player names are auto-generated on first access (e.g., `BOLDFALCON`, `SWIFTPANDA`). Players can override with `setPlayerName()`.
|
|
64
|
+
|
|
64
65
|
```typescript
|
|
65
66
|
session.getPlayerGuid(); // Get or create persistent GUID
|
|
66
|
-
session.getPlayerName(); // Get stored name
|
|
67
|
+
session.getPlayerName(); // Get stored name (auto-generated if first time)
|
|
67
68
|
session.setPlayerName(name); // Store name locally (doesn't update server)
|
|
69
|
+
session.hasExplicitPlayerName(); // true if player chose their name
|
|
68
70
|
|
|
69
71
|
// Validate a name (pure function)
|
|
70
72
|
const validated = session.validateName(' Ace Pilot! ');
|
|
@@ -271,6 +273,16 @@ class GameOverScene extends Phaser.Scene {
|
|
|
271
273
|
|
|
272
274
|
## Utilities
|
|
273
275
|
|
|
276
|
+
### generatePlayerName
|
|
277
|
+
|
|
278
|
+
Generate random AdjectiveNoun player names:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
import { generatePlayerName } from 'keeperboard';
|
|
282
|
+
|
|
283
|
+
const name = generatePlayerName(); // 'BOLDFALCON', 'SWIFTPANDA', etc.
|
|
284
|
+
```
|
|
285
|
+
|
|
274
286
|
### PlayerIdentity
|
|
275
287
|
|
|
276
288
|
Standalone helper for localStorage identity management:
|
package/dist/index.d.mts
CHANGED
|
@@ -102,8 +102,6 @@ interface SessionConfig {
|
|
|
102
102
|
identity?: {
|
|
103
103
|
keyPrefix?: string;
|
|
104
104
|
};
|
|
105
|
-
/** Default player name when none has been set (default: "ANON") */
|
|
106
|
-
defaultPlayerName?: string;
|
|
107
105
|
/** TTL cache configuration for getSnapshot() */
|
|
108
106
|
cache?: {
|
|
109
107
|
ttlMs: number;
|
|
@@ -141,8 +139,6 @@ interface NameValidationOptions {
|
|
|
141
139
|
minLength?: number;
|
|
142
140
|
/** Maximum length — input is truncated to this (default 12). */
|
|
143
141
|
maxLength?: number;
|
|
144
|
-
/** Convert to uppercase (default true). */
|
|
145
|
-
uppercase?: boolean;
|
|
146
142
|
/** Regex of allowed characters applied after case conversion (default /[^A-Z0-9_]/g removes non-matching). */
|
|
147
143
|
allowedPattern?: RegExp;
|
|
148
144
|
}
|
|
@@ -303,7 +299,6 @@ declare class KeeperBoardSession {
|
|
|
303
299
|
private readonly client;
|
|
304
300
|
private readonly identity;
|
|
305
301
|
private readonly leaderboard;
|
|
306
|
-
private readonly defaultPlayerName;
|
|
307
302
|
private readonly cache;
|
|
308
303
|
private readonly retryQueue;
|
|
309
304
|
private cachedLimit;
|
|
@@ -311,10 +306,12 @@ declare class KeeperBoardSession {
|
|
|
311
306
|
constructor(config: SessionConfig);
|
|
312
307
|
/** Get or create a persistent player GUID. */
|
|
313
308
|
getPlayerGuid(): string;
|
|
314
|
-
/** Get the stored player name,
|
|
309
|
+
/** Get the stored player name, auto-generating one if none exists. */
|
|
315
310
|
getPlayerName(): string;
|
|
316
311
|
/** Store a player name locally. Does NOT update the server — call updatePlayerName() for that. */
|
|
317
312
|
setPlayerName(name: string): void;
|
|
313
|
+
/** Check if the player has explicitly set a name (vs auto-generated). */
|
|
314
|
+
hasExplicitPlayerName(): boolean;
|
|
318
315
|
/** Validate a name using configurable rules. Returns sanitized string or null. */
|
|
319
316
|
validateName(input: string, options?: NameValidationOptions): string | null;
|
|
320
317
|
/**
|
|
@@ -369,6 +366,7 @@ declare class PlayerIdentity {
|
|
|
369
366
|
private readonly keyPrefix;
|
|
370
367
|
private readonly guidKey;
|
|
371
368
|
private readonly nameKey;
|
|
369
|
+
private readonly nameAutoKey;
|
|
372
370
|
constructor(config?: PlayerIdentityConfig);
|
|
373
371
|
/**
|
|
374
372
|
* Get the stored player GUID, or null if none exists.
|
|
@@ -391,6 +389,15 @@ declare class PlayerIdentity {
|
|
|
391
389
|
* Set the player name in localStorage.
|
|
392
390
|
*/
|
|
393
391
|
setPlayerName(name: string): void;
|
|
392
|
+
/**
|
|
393
|
+
* Get the stored player name, creating an auto-generated one if it doesn't exist.
|
|
394
|
+
* Uses AdjectiveNounNumber pattern (e.g., ArcaneBlob99).
|
|
395
|
+
*/
|
|
396
|
+
getOrCreatePlayerName(): string;
|
|
397
|
+
/**
|
|
398
|
+
* Check if the current player name was auto-generated (vs explicitly set by user).
|
|
399
|
+
*/
|
|
400
|
+
isAutoGeneratedName(): boolean;
|
|
394
401
|
/**
|
|
395
402
|
* Clear all stored player identity data.
|
|
396
403
|
*/
|
|
@@ -415,18 +422,33 @@ declare class PlayerIdentity {
|
|
|
415
422
|
* Validate and sanitize a player name.
|
|
416
423
|
*
|
|
417
424
|
* 1. Trims whitespace
|
|
418
|
-
* 2.
|
|
419
|
-
* 3.
|
|
420
|
-
* 4.
|
|
421
|
-
* 5. Returns `null` if result is shorter than `minLength`
|
|
425
|
+
* 2. Strips characters not matching `allowedPattern`
|
|
426
|
+
* 3. Truncates to `maxLength`
|
|
427
|
+
* 4. Returns `null` if result is shorter than `minLength`
|
|
422
428
|
*
|
|
423
429
|
* @example
|
|
424
|
-
* validateName(' Ace Pilot! ') // '
|
|
425
|
-
* validateName('ab') // '
|
|
430
|
+
* validateName(' Ace Pilot! ') // 'AcePilot'
|
|
431
|
+
* validateName('ab') // 'ab'
|
|
426
432
|
* validateName('x') // null (too short)
|
|
427
433
|
*/
|
|
428
434
|
declare function validateName(input: string, options?: NameValidationOptions): string | null;
|
|
429
435
|
|
|
436
|
+
/**
|
|
437
|
+
* Auto-generated player name system.
|
|
438
|
+
* Generates random AdjectiveNounNumber names (e.g., ArcaneBlob99).
|
|
439
|
+
* Names are PascalCase words plus a numeric suffix, and fit within 4-12 characters.
|
|
440
|
+
*/
|
|
441
|
+
/**
|
|
442
|
+
* Generate a random player name in the format AdjectiveNoun1-99.
|
|
443
|
+
* Returns a PascalCase string with length 4-12 characters (fits validateName rules).
|
|
444
|
+
* ~990,000 unique combinations possible.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* generatePlayerName() // 'ArcaneBlob99'
|
|
448
|
+
* generatePlayerName() // 'CosmicViper42'
|
|
449
|
+
*/
|
|
450
|
+
declare function generatePlayerName(): string;
|
|
451
|
+
|
|
430
452
|
/**
|
|
431
453
|
* Generic TTL cache with in-flight deduplication and background refresh.
|
|
432
454
|
*
|
|
@@ -488,4 +510,4 @@ declare class RetryQueue {
|
|
|
488
510
|
clear(): void;
|
|
489
511
|
}
|
|
490
512
|
|
|
491
|
-
export { Cache, type ClaimResponse, type ClaimResult, type ClaimScoreOptions, type GetLeaderboardOptions, type GetPlayerRankOptions, type HealthResponse, type HealthResult, KeeperBoardClient, type KeeperBoardConfig, KeeperBoardError, KeeperBoardSession, type LeaderboardEntry, type LeaderboardResponse, type LeaderboardResult, type NameValidationOptions, PlayerIdentity, type PlayerIdentityConfig, type PlayerResponse, type PlayerResult, type ResetSchedule, RetryQueue, type ScoreResponse, type ScoreResult, type ScoreSubmission, type SessionConfig, type SessionScoreResult, type SnapshotEntry, type SnapshotResult, type SubmitScoreOptions, type UpdatePlayerNameOptions, validateName };
|
|
513
|
+
export { Cache, type ClaimResponse, type ClaimResult, type ClaimScoreOptions, type GetLeaderboardOptions, type GetPlayerRankOptions, type HealthResponse, type HealthResult, KeeperBoardClient, type KeeperBoardConfig, KeeperBoardError, KeeperBoardSession, type LeaderboardEntry, type LeaderboardResponse, type LeaderboardResult, type NameValidationOptions, PlayerIdentity, type PlayerIdentityConfig, type PlayerResponse, type PlayerResult, type ResetSchedule, RetryQueue, type ScoreResponse, type ScoreResult, type ScoreSubmission, type SessionConfig, type SessionScoreResult, type SnapshotEntry, type SnapshotResult, type SubmitScoreOptions, type UpdatePlayerNameOptions, generatePlayerName, validateName };
|
package/dist/index.d.ts
CHANGED
|
@@ -102,8 +102,6 @@ interface SessionConfig {
|
|
|
102
102
|
identity?: {
|
|
103
103
|
keyPrefix?: string;
|
|
104
104
|
};
|
|
105
|
-
/** Default player name when none has been set (default: "ANON") */
|
|
106
|
-
defaultPlayerName?: string;
|
|
107
105
|
/** TTL cache configuration for getSnapshot() */
|
|
108
106
|
cache?: {
|
|
109
107
|
ttlMs: number;
|
|
@@ -141,8 +139,6 @@ interface NameValidationOptions {
|
|
|
141
139
|
minLength?: number;
|
|
142
140
|
/** Maximum length — input is truncated to this (default 12). */
|
|
143
141
|
maxLength?: number;
|
|
144
|
-
/** Convert to uppercase (default true). */
|
|
145
|
-
uppercase?: boolean;
|
|
146
142
|
/** Regex of allowed characters applied after case conversion (default /[^A-Z0-9_]/g removes non-matching). */
|
|
147
143
|
allowedPattern?: RegExp;
|
|
148
144
|
}
|
|
@@ -303,7 +299,6 @@ declare class KeeperBoardSession {
|
|
|
303
299
|
private readonly client;
|
|
304
300
|
private readonly identity;
|
|
305
301
|
private readonly leaderboard;
|
|
306
|
-
private readonly defaultPlayerName;
|
|
307
302
|
private readonly cache;
|
|
308
303
|
private readonly retryQueue;
|
|
309
304
|
private cachedLimit;
|
|
@@ -311,10 +306,12 @@ declare class KeeperBoardSession {
|
|
|
311
306
|
constructor(config: SessionConfig);
|
|
312
307
|
/** Get or create a persistent player GUID. */
|
|
313
308
|
getPlayerGuid(): string;
|
|
314
|
-
/** Get the stored player name,
|
|
309
|
+
/** Get the stored player name, auto-generating one if none exists. */
|
|
315
310
|
getPlayerName(): string;
|
|
316
311
|
/** Store a player name locally. Does NOT update the server — call updatePlayerName() for that. */
|
|
317
312
|
setPlayerName(name: string): void;
|
|
313
|
+
/** Check if the player has explicitly set a name (vs auto-generated). */
|
|
314
|
+
hasExplicitPlayerName(): boolean;
|
|
318
315
|
/** Validate a name using configurable rules. Returns sanitized string or null. */
|
|
319
316
|
validateName(input: string, options?: NameValidationOptions): string | null;
|
|
320
317
|
/**
|
|
@@ -369,6 +366,7 @@ declare class PlayerIdentity {
|
|
|
369
366
|
private readonly keyPrefix;
|
|
370
367
|
private readonly guidKey;
|
|
371
368
|
private readonly nameKey;
|
|
369
|
+
private readonly nameAutoKey;
|
|
372
370
|
constructor(config?: PlayerIdentityConfig);
|
|
373
371
|
/**
|
|
374
372
|
* Get the stored player GUID, or null if none exists.
|
|
@@ -391,6 +389,15 @@ declare class PlayerIdentity {
|
|
|
391
389
|
* Set the player name in localStorage.
|
|
392
390
|
*/
|
|
393
391
|
setPlayerName(name: string): void;
|
|
392
|
+
/**
|
|
393
|
+
* Get the stored player name, creating an auto-generated one if it doesn't exist.
|
|
394
|
+
* Uses AdjectiveNounNumber pattern (e.g., ArcaneBlob99).
|
|
395
|
+
*/
|
|
396
|
+
getOrCreatePlayerName(): string;
|
|
397
|
+
/**
|
|
398
|
+
* Check if the current player name was auto-generated (vs explicitly set by user).
|
|
399
|
+
*/
|
|
400
|
+
isAutoGeneratedName(): boolean;
|
|
394
401
|
/**
|
|
395
402
|
* Clear all stored player identity data.
|
|
396
403
|
*/
|
|
@@ -415,18 +422,33 @@ declare class PlayerIdentity {
|
|
|
415
422
|
* Validate and sanitize a player name.
|
|
416
423
|
*
|
|
417
424
|
* 1. Trims whitespace
|
|
418
|
-
* 2.
|
|
419
|
-
* 3.
|
|
420
|
-
* 4.
|
|
421
|
-
* 5. Returns `null` if result is shorter than `minLength`
|
|
425
|
+
* 2. Strips characters not matching `allowedPattern`
|
|
426
|
+
* 3. Truncates to `maxLength`
|
|
427
|
+
* 4. Returns `null` if result is shorter than `minLength`
|
|
422
428
|
*
|
|
423
429
|
* @example
|
|
424
|
-
* validateName(' Ace Pilot! ') // '
|
|
425
|
-
* validateName('ab') // '
|
|
430
|
+
* validateName(' Ace Pilot! ') // 'AcePilot'
|
|
431
|
+
* validateName('ab') // 'ab'
|
|
426
432
|
* validateName('x') // null (too short)
|
|
427
433
|
*/
|
|
428
434
|
declare function validateName(input: string, options?: NameValidationOptions): string | null;
|
|
429
435
|
|
|
436
|
+
/**
|
|
437
|
+
* Auto-generated player name system.
|
|
438
|
+
* Generates random AdjectiveNounNumber names (e.g., ArcaneBlob99).
|
|
439
|
+
* Names are PascalCase words plus a numeric suffix, and fit within 4-12 characters.
|
|
440
|
+
*/
|
|
441
|
+
/**
|
|
442
|
+
* Generate a random player name in the format AdjectiveNoun1-99.
|
|
443
|
+
* Returns a PascalCase string with length 4-12 characters (fits validateName rules).
|
|
444
|
+
* ~990,000 unique combinations possible.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* generatePlayerName() // 'ArcaneBlob99'
|
|
448
|
+
* generatePlayerName() // 'CosmicViper42'
|
|
449
|
+
*/
|
|
450
|
+
declare function generatePlayerName(): string;
|
|
451
|
+
|
|
430
452
|
/**
|
|
431
453
|
* Generic TTL cache with in-flight deduplication and background refresh.
|
|
432
454
|
*
|
|
@@ -488,4 +510,4 @@ declare class RetryQueue {
|
|
|
488
510
|
clear(): void;
|
|
489
511
|
}
|
|
490
512
|
|
|
491
|
-
export { Cache, type ClaimResponse, type ClaimResult, type ClaimScoreOptions, type GetLeaderboardOptions, type GetPlayerRankOptions, type HealthResponse, type HealthResult, KeeperBoardClient, type KeeperBoardConfig, KeeperBoardError, KeeperBoardSession, type LeaderboardEntry, type LeaderboardResponse, type LeaderboardResult, type NameValidationOptions, PlayerIdentity, type PlayerIdentityConfig, type PlayerResponse, type PlayerResult, type ResetSchedule, RetryQueue, type ScoreResponse, type ScoreResult, type ScoreSubmission, type SessionConfig, type SessionScoreResult, type SnapshotEntry, type SnapshotResult, type SubmitScoreOptions, type UpdatePlayerNameOptions, validateName };
|
|
513
|
+
export { Cache, type ClaimResponse, type ClaimResult, type ClaimScoreOptions, type GetLeaderboardOptions, type GetPlayerRankOptions, type HealthResponse, type HealthResult, KeeperBoardClient, type KeeperBoardConfig, KeeperBoardError, KeeperBoardSession, type LeaderboardEntry, type LeaderboardResponse, type LeaderboardResult, type NameValidationOptions, PlayerIdentity, type PlayerIdentityConfig, type PlayerResponse, type PlayerResult, type ResetSchedule, RetryQueue, type ScoreResponse, type ScoreResult, type ScoreSubmission, type SessionConfig, type SessionScoreResult, type SnapshotEntry, type SnapshotResult, type SubmitScoreOptions, type UpdatePlayerNameOptions, generatePlayerName, validateName };
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
KeeperBoardSession: () => KeeperBoardSession,
|
|
27
27
|
PlayerIdentity: () => PlayerIdentity,
|
|
28
28
|
RetryQueue: () => RetryQueue,
|
|
29
|
+
generatePlayerName: () => generatePlayerName,
|
|
29
30
|
validateName: () => validateName
|
|
30
31
|
});
|
|
31
32
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -261,6 +262,220 @@ var _KeeperBoardClient = class _KeeperBoardClient {
|
|
|
261
262
|
_KeeperBoardClient.DEFAULT_API_URL = "https://keeperboard.vercel.app";
|
|
262
263
|
var KeeperBoardClient = _KeeperBoardClient;
|
|
263
264
|
|
|
265
|
+
// src/nameGenerator.ts
|
|
266
|
+
var MAX_BASE_LENGTH = 10;
|
|
267
|
+
var ADJECTIVES = [
|
|
268
|
+
"Arcane",
|
|
269
|
+
"Astro",
|
|
270
|
+
"Blazing",
|
|
271
|
+
"Bouncy",
|
|
272
|
+
"Brassy",
|
|
273
|
+
"Brisk",
|
|
274
|
+
"Bubbly",
|
|
275
|
+
"Chaotic",
|
|
276
|
+
"Cheeky",
|
|
277
|
+
"Chill",
|
|
278
|
+
"Chunky",
|
|
279
|
+
"Cloaked",
|
|
280
|
+
"Cosmic",
|
|
281
|
+
"Crimson",
|
|
282
|
+
"Crispy",
|
|
283
|
+
"Dashing",
|
|
284
|
+
"Dizzy",
|
|
285
|
+
"Dynamic",
|
|
286
|
+
"Electric",
|
|
287
|
+
"Epic",
|
|
288
|
+
"Feisty",
|
|
289
|
+
"Fiery",
|
|
290
|
+
"Flashy",
|
|
291
|
+
"Frosty",
|
|
292
|
+
"Funky",
|
|
293
|
+
"Furious",
|
|
294
|
+
"Galactic",
|
|
295
|
+
"Glitchy",
|
|
296
|
+
"Golden",
|
|
297
|
+
"Goofy",
|
|
298
|
+
"Gritty",
|
|
299
|
+
"Groovy",
|
|
300
|
+
"Hyper",
|
|
301
|
+
"Icy",
|
|
302
|
+
"Inky",
|
|
303
|
+
"Jazzy",
|
|
304
|
+
"Jolly",
|
|
305
|
+
"Jumpy",
|
|
306
|
+
"Laser",
|
|
307
|
+
"Legendary",
|
|
308
|
+
"Loud",
|
|
309
|
+
"Lucky",
|
|
310
|
+
"Lunar",
|
|
311
|
+
"Madcap",
|
|
312
|
+
"Magic",
|
|
313
|
+
"Majestic",
|
|
314
|
+
"Meteor",
|
|
315
|
+
"Mighty",
|
|
316
|
+
"Minty",
|
|
317
|
+
"Mystic",
|
|
318
|
+
"Neon",
|
|
319
|
+
"Nimble",
|
|
320
|
+
"Nova",
|
|
321
|
+
"Nuclear",
|
|
322
|
+
"Omega",
|
|
323
|
+
"Orbital",
|
|
324
|
+
"Peppy",
|
|
325
|
+
"Phantom",
|
|
326
|
+
"Pixel",
|
|
327
|
+
"Plasma",
|
|
328
|
+
"Polished",
|
|
329
|
+
"Primal",
|
|
330
|
+
"Quantum",
|
|
331
|
+
"Quick",
|
|
332
|
+
"Radiant",
|
|
333
|
+
"Rampaging",
|
|
334
|
+
"Razor",
|
|
335
|
+
"Rebel",
|
|
336
|
+
"Retro",
|
|
337
|
+
"Rogue",
|
|
338
|
+
"Rowdy",
|
|
339
|
+
"Savage",
|
|
340
|
+
"Shadow",
|
|
341
|
+
"Shiny",
|
|
342
|
+
"Silly",
|
|
343
|
+
"Sketchy",
|
|
344
|
+
"Skybound",
|
|
345
|
+
"Slick",
|
|
346
|
+
"Snappy",
|
|
347
|
+
"Solar",
|
|
348
|
+
"Sonic",
|
|
349
|
+
"Sparky",
|
|
350
|
+
"Speedy",
|
|
351
|
+
"Spiky",
|
|
352
|
+
"Starry",
|
|
353
|
+
"Stealthy",
|
|
354
|
+
"Stormy",
|
|
355
|
+
"Supreme",
|
|
356
|
+
"Swift",
|
|
357
|
+
"Thunder",
|
|
358
|
+
"Turbo",
|
|
359
|
+
"Twilight",
|
|
360
|
+
"Ultra",
|
|
361
|
+
"Vibrant",
|
|
362
|
+
"Warped",
|
|
363
|
+
"Wicked",
|
|
364
|
+
"Wild",
|
|
365
|
+
"Wizard",
|
|
366
|
+
"Zappy",
|
|
367
|
+
"Zesty"
|
|
368
|
+
];
|
|
369
|
+
var NOUNS = [
|
|
370
|
+
"Aardvark",
|
|
371
|
+
"Asteroid",
|
|
372
|
+
"Badger",
|
|
373
|
+
"Bandit",
|
|
374
|
+
"Banshee",
|
|
375
|
+
"Beacon",
|
|
376
|
+
"Beetle",
|
|
377
|
+
"Blaster",
|
|
378
|
+
"Blob",
|
|
379
|
+
"Boomer",
|
|
380
|
+
"Bot",
|
|
381
|
+
"Brawler",
|
|
382
|
+
"Buccaneer",
|
|
383
|
+
"Buffalo",
|
|
384
|
+
"Cannon",
|
|
385
|
+
"Captain",
|
|
386
|
+
"Caribou",
|
|
387
|
+
"Charger",
|
|
388
|
+
"Cheetah",
|
|
389
|
+
"Chimera",
|
|
390
|
+
"Cobra",
|
|
391
|
+
"Comet",
|
|
392
|
+
"Cosmonaut",
|
|
393
|
+
"Cougar",
|
|
394
|
+
"Coyote",
|
|
395
|
+
"Cyborg",
|
|
396
|
+
"Dagger",
|
|
397
|
+
"Defender",
|
|
398
|
+
"Dino",
|
|
399
|
+
"Dragon",
|
|
400
|
+
"Drifter",
|
|
401
|
+
"Drone",
|
|
402
|
+
"Duck",
|
|
403
|
+
"Eagle",
|
|
404
|
+
"Eel",
|
|
405
|
+
"Falcon",
|
|
406
|
+
"Ferret",
|
|
407
|
+
"Fireball",
|
|
408
|
+
"Fox",
|
|
409
|
+
"Fury",
|
|
410
|
+
"Gazelle",
|
|
411
|
+
"Ghost",
|
|
412
|
+
"Gizmo",
|
|
413
|
+
"Gladiator",
|
|
414
|
+
"Goblin",
|
|
415
|
+
"Griffin",
|
|
416
|
+
"Hammer",
|
|
417
|
+
"Hawk",
|
|
418
|
+
"Hero",
|
|
419
|
+
"Hydra",
|
|
420
|
+
"Iguana",
|
|
421
|
+
"Jaguar",
|
|
422
|
+
"Jester",
|
|
423
|
+
"Jetpack",
|
|
424
|
+
"Jinx",
|
|
425
|
+
"Kangaroo",
|
|
426
|
+
"Katana",
|
|
427
|
+
"Kraken",
|
|
428
|
+
"Lancer",
|
|
429
|
+
"Laser",
|
|
430
|
+
"Legend",
|
|
431
|
+
"Lemur",
|
|
432
|
+
"Leopard",
|
|
433
|
+
"Lion",
|
|
434
|
+
"Luchador",
|
|
435
|
+
"Lynx",
|
|
436
|
+
"Maverick",
|
|
437
|
+
"Meteor",
|
|
438
|
+
"Monkey",
|
|
439
|
+
"Monsoon",
|
|
440
|
+
"Moose",
|
|
441
|
+
"Ninja",
|
|
442
|
+
"Nova",
|
|
443
|
+
"Octopus",
|
|
444
|
+
"Oracle",
|
|
445
|
+
"Otter",
|
|
446
|
+
"Panther",
|
|
447
|
+
"Phoenix",
|
|
448
|
+
"Pirate",
|
|
449
|
+
"Pixel",
|
|
450
|
+
"Puma",
|
|
451
|
+
"Quasar",
|
|
452
|
+
"Racer",
|
|
453
|
+
"Raptor",
|
|
454
|
+
"Raven",
|
|
455
|
+
"Reactor",
|
|
456
|
+
"Rocket",
|
|
457
|
+
"Ronin",
|
|
458
|
+
"Saber",
|
|
459
|
+
"Scorpion",
|
|
460
|
+
"Shark",
|
|
461
|
+
"Spartan",
|
|
462
|
+
"Sphinx",
|
|
463
|
+
"Sprinter",
|
|
464
|
+
"Stallion",
|
|
465
|
+
"Tiger",
|
|
466
|
+
"Titan",
|
|
467
|
+
"Viking",
|
|
468
|
+
"Viper",
|
|
469
|
+
"Wizard"
|
|
470
|
+
];
|
|
471
|
+
function generatePlayerName() {
|
|
472
|
+
const adjective = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
|
|
473
|
+
const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
|
|
474
|
+
const number = Math.floor(Math.random() * 99) + 1;
|
|
475
|
+
const base = (adjective + noun).slice(0, MAX_BASE_LENGTH);
|
|
476
|
+
return `${base}${number}`;
|
|
477
|
+
}
|
|
478
|
+
|
|
264
479
|
// src/PlayerIdentity.ts
|
|
265
480
|
var DEFAULT_KEY_PREFIX = "keeperboard_";
|
|
266
481
|
var PlayerIdentity = class {
|
|
@@ -268,6 +483,7 @@ var PlayerIdentity = class {
|
|
|
268
483
|
this.keyPrefix = config.keyPrefix ?? DEFAULT_KEY_PREFIX;
|
|
269
484
|
this.guidKey = `${this.keyPrefix}player_guid`;
|
|
270
485
|
this.nameKey = `${this.keyPrefix}player_name`;
|
|
486
|
+
this.nameAutoKey = `${this.keyPrefix}player_name_auto`;
|
|
271
487
|
}
|
|
272
488
|
/**
|
|
273
489
|
* Get the stored player GUID, or null if none exists.
|
|
@@ -316,6 +532,31 @@ var PlayerIdentity = class {
|
|
|
316
532
|
return;
|
|
317
533
|
}
|
|
318
534
|
localStorage.setItem(this.nameKey, name);
|
|
535
|
+
localStorage.removeItem(this.nameAutoKey);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Get the stored player name, creating an auto-generated one if it doesn't exist.
|
|
539
|
+
* Uses AdjectiveNounNumber pattern (e.g., ArcaneBlob99).
|
|
540
|
+
*/
|
|
541
|
+
getOrCreatePlayerName() {
|
|
542
|
+
let name = this.getPlayerName();
|
|
543
|
+
if (!name) {
|
|
544
|
+
name = generatePlayerName();
|
|
545
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
546
|
+
localStorage.setItem(this.nameKey, name);
|
|
547
|
+
localStorage.setItem(this.nameAutoKey, "true");
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return name;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Check if the current player name was auto-generated (vs explicitly set by user).
|
|
554
|
+
*/
|
|
555
|
+
isAutoGeneratedName() {
|
|
556
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
return localStorage.getItem(this.nameAutoKey) === "true";
|
|
319
560
|
}
|
|
320
561
|
/**
|
|
321
562
|
* Clear all stored player identity data.
|
|
@@ -326,6 +567,7 @@ var PlayerIdentity = class {
|
|
|
326
567
|
}
|
|
327
568
|
localStorage.removeItem(this.guidKey);
|
|
328
569
|
localStorage.removeItem(this.nameKey);
|
|
570
|
+
localStorage.removeItem(this.nameAutoKey);
|
|
329
571
|
}
|
|
330
572
|
/**
|
|
331
573
|
* Check if player identity is stored.
|
|
@@ -478,16 +720,12 @@ var RetryQueue = class {
|
|
|
478
720
|
var DEFAULTS = {
|
|
479
721
|
minLength: 2,
|
|
480
722
|
maxLength: 12,
|
|
481
|
-
|
|
482
|
-
allowedPattern: /[^A-Z0-9_]/g
|
|
723
|
+
allowedPattern: /[^A-Za-z0-9_]/g
|
|
483
724
|
};
|
|
484
725
|
function validateName(input, options) {
|
|
485
726
|
const opts = { ...DEFAULTS, ...options };
|
|
486
727
|
let name = input.trim();
|
|
487
|
-
|
|
488
|
-
name = name.toUpperCase();
|
|
489
|
-
}
|
|
490
|
-
const pattern = options?.allowedPattern ?? (opts.uppercase ? /[^A-Z0-9_]/g : /[^A-Za-z0-9_]/g);
|
|
728
|
+
const pattern = options?.allowedPattern ?? /[^A-Za-z0-9_]/g;
|
|
491
729
|
name = name.replace(pattern, "");
|
|
492
730
|
name = name.substring(0, opts.maxLength);
|
|
493
731
|
if (name.length < opts.minLength) {
|
|
@@ -509,7 +747,6 @@ var KeeperBoardSession = class {
|
|
|
509
747
|
});
|
|
510
748
|
this.identity = new PlayerIdentity(config.identity);
|
|
511
749
|
this.leaderboard = config.leaderboard;
|
|
512
|
-
this.defaultPlayerName = config.defaultPlayerName ?? "ANON";
|
|
513
750
|
this.cache = config.cache ? new Cache(config.cache.ttlMs) : null;
|
|
514
751
|
this.retryQueue = config.retry ? new RetryQueue(
|
|
515
752
|
`keeperboard_retry_${config.leaderboard}`,
|
|
@@ -523,14 +760,18 @@ var KeeperBoardSession = class {
|
|
|
523
760
|
getPlayerGuid() {
|
|
524
761
|
return this.identity.getOrCreatePlayerGuid();
|
|
525
762
|
}
|
|
526
|
-
/** Get the stored player name,
|
|
763
|
+
/** Get the stored player name, auto-generating one if none exists. */
|
|
527
764
|
getPlayerName() {
|
|
528
|
-
return this.identity.
|
|
765
|
+
return this.identity.getOrCreatePlayerName();
|
|
529
766
|
}
|
|
530
767
|
/** Store a player name locally. Does NOT update the server — call updatePlayerName() for that. */
|
|
531
768
|
setPlayerName(name) {
|
|
532
769
|
this.identity.setPlayerName(name);
|
|
533
770
|
}
|
|
771
|
+
/** Check if the player has explicitly set a name (vs auto-generated). */
|
|
772
|
+
hasExplicitPlayerName() {
|
|
773
|
+
return this.identity.getPlayerName() !== null && !this.identity.isAutoGeneratedName();
|
|
774
|
+
}
|
|
534
775
|
/** Validate a name using configurable rules. Returns sanitized string or null. */
|
|
535
776
|
validateName(input, options) {
|
|
536
777
|
return validateName(input, options);
|
|
@@ -680,5 +921,6 @@ var KeeperBoardSession = class {
|
|
|
680
921
|
KeeperBoardSession,
|
|
681
922
|
PlayerIdentity,
|
|
682
923
|
RetryQueue,
|
|
924
|
+
generatePlayerName,
|
|
683
925
|
validateName
|
|
684
926
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -229,6 +229,220 @@ var _KeeperBoardClient = class _KeeperBoardClient {
|
|
|
229
229
|
_KeeperBoardClient.DEFAULT_API_URL = "https://keeperboard.vercel.app";
|
|
230
230
|
var KeeperBoardClient = _KeeperBoardClient;
|
|
231
231
|
|
|
232
|
+
// src/nameGenerator.ts
|
|
233
|
+
var MAX_BASE_LENGTH = 10;
|
|
234
|
+
var ADJECTIVES = [
|
|
235
|
+
"Arcane",
|
|
236
|
+
"Astro",
|
|
237
|
+
"Blazing",
|
|
238
|
+
"Bouncy",
|
|
239
|
+
"Brassy",
|
|
240
|
+
"Brisk",
|
|
241
|
+
"Bubbly",
|
|
242
|
+
"Chaotic",
|
|
243
|
+
"Cheeky",
|
|
244
|
+
"Chill",
|
|
245
|
+
"Chunky",
|
|
246
|
+
"Cloaked",
|
|
247
|
+
"Cosmic",
|
|
248
|
+
"Crimson",
|
|
249
|
+
"Crispy",
|
|
250
|
+
"Dashing",
|
|
251
|
+
"Dizzy",
|
|
252
|
+
"Dynamic",
|
|
253
|
+
"Electric",
|
|
254
|
+
"Epic",
|
|
255
|
+
"Feisty",
|
|
256
|
+
"Fiery",
|
|
257
|
+
"Flashy",
|
|
258
|
+
"Frosty",
|
|
259
|
+
"Funky",
|
|
260
|
+
"Furious",
|
|
261
|
+
"Galactic",
|
|
262
|
+
"Glitchy",
|
|
263
|
+
"Golden",
|
|
264
|
+
"Goofy",
|
|
265
|
+
"Gritty",
|
|
266
|
+
"Groovy",
|
|
267
|
+
"Hyper",
|
|
268
|
+
"Icy",
|
|
269
|
+
"Inky",
|
|
270
|
+
"Jazzy",
|
|
271
|
+
"Jolly",
|
|
272
|
+
"Jumpy",
|
|
273
|
+
"Laser",
|
|
274
|
+
"Legendary",
|
|
275
|
+
"Loud",
|
|
276
|
+
"Lucky",
|
|
277
|
+
"Lunar",
|
|
278
|
+
"Madcap",
|
|
279
|
+
"Magic",
|
|
280
|
+
"Majestic",
|
|
281
|
+
"Meteor",
|
|
282
|
+
"Mighty",
|
|
283
|
+
"Minty",
|
|
284
|
+
"Mystic",
|
|
285
|
+
"Neon",
|
|
286
|
+
"Nimble",
|
|
287
|
+
"Nova",
|
|
288
|
+
"Nuclear",
|
|
289
|
+
"Omega",
|
|
290
|
+
"Orbital",
|
|
291
|
+
"Peppy",
|
|
292
|
+
"Phantom",
|
|
293
|
+
"Pixel",
|
|
294
|
+
"Plasma",
|
|
295
|
+
"Polished",
|
|
296
|
+
"Primal",
|
|
297
|
+
"Quantum",
|
|
298
|
+
"Quick",
|
|
299
|
+
"Radiant",
|
|
300
|
+
"Rampaging",
|
|
301
|
+
"Razor",
|
|
302
|
+
"Rebel",
|
|
303
|
+
"Retro",
|
|
304
|
+
"Rogue",
|
|
305
|
+
"Rowdy",
|
|
306
|
+
"Savage",
|
|
307
|
+
"Shadow",
|
|
308
|
+
"Shiny",
|
|
309
|
+
"Silly",
|
|
310
|
+
"Sketchy",
|
|
311
|
+
"Skybound",
|
|
312
|
+
"Slick",
|
|
313
|
+
"Snappy",
|
|
314
|
+
"Solar",
|
|
315
|
+
"Sonic",
|
|
316
|
+
"Sparky",
|
|
317
|
+
"Speedy",
|
|
318
|
+
"Spiky",
|
|
319
|
+
"Starry",
|
|
320
|
+
"Stealthy",
|
|
321
|
+
"Stormy",
|
|
322
|
+
"Supreme",
|
|
323
|
+
"Swift",
|
|
324
|
+
"Thunder",
|
|
325
|
+
"Turbo",
|
|
326
|
+
"Twilight",
|
|
327
|
+
"Ultra",
|
|
328
|
+
"Vibrant",
|
|
329
|
+
"Warped",
|
|
330
|
+
"Wicked",
|
|
331
|
+
"Wild",
|
|
332
|
+
"Wizard",
|
|
333
|
+
"Zappy",
|
|
334
|
+
"Zesty"
|
|
335
|
+
];
|
|
336
|
+
var NOUNS = [
|
|
337
|
+
"Aardvark",
|
|
338
|
+
"Asteroid",
|
|
339
|
+
"Badger",
|
|
340
|
+
"Bandit",
|
|
341
|
+
"Banshee",
|
|
342
|
+
"Beacon",
|
|
343
|
+
"Beetle",
|
|
344
|
+
"Blaster",
|
|
345
|
+
"Blob",
|
|
346
|
+
"Boomer",
|
|
347
|
+
"Bot",
|
|
348
|
+
"Brawler",
|
|
349
|
+
"Buccaneer",
|
|
350
|
+
"Buffalo",
|
|
351
|
+
"Cannon",
|
|
352
|
+
"Captain",
|
|
353
|
+
"Caribou",
|
|
354
|
+
"Charger",
|
|
355
|
+
"Cheetah",
|
|
356
|
+
"Chimera",
|
|
357
|
+
"Cobra",
|
|
358
|
+
"Comet",
|
|
359
|
+
"Cosmonaut",
|
|
360
|
+
"Cougar",
|
|
361
|
+
"Coyote",
|
|
362
|
+
"Cyborg",
|
|
363
|
+
"Dagger",
|
|
364
|
+
"Defender",
|
|
365
|
+
"Dino",
|
|
366
|
+
"Dragon",
|
|
367
|
+
"Drifter",
|
|
368
|
+
"Drone",
|
|
369
|
+
"Duck",
|
|
370
|
+
"Eagle",
|
|
371
|
+
"Eel",
|
|
372
|
+
"Falcon",
|
|
373
|
+
"Ferret",
|
|
374
|
+
"Fireball",
|
|
375
|
+
"Fox",
|
|
376
|
+
"Fury",
|
|
377
|
+
"Gazelle",
|
|
378
|
+
"Ghost",
|
|
379
|
+
"Gizmo",
|
|
380
|
+
"Gladiator",
|
|
381
|
+
"Goblin",
|
|
382
|
+
"Griffin",
|
|
383
|
+
"Hammer",
|
|
384
|
+
"Hawk",
|
|
385
|
+
"Hero",
|
|
386
|
+
"Hydra",
|
|
387
|
+
"Iguana",
|
|
388
|
+
"Jaguar",
|
|
389
|
+
"Jester",
|
|
390
|
+
"Jetpack",
|
|
391
|
+
"Jinx",
|
|
392
|
+
"Kangaroo",
|
|
393
|
+
"Katana",
|
|
394
|
+
"Kraken",
|
|
395
|
+
"Lancer",
|
|
396
|
+
"Laser",
|
|
397
|
+
"Legend",
|
|
398
|
+
"Lemur",
|
|
399
|
+
"Leopard",
|
|
400
|
+
"Lion",
|
|
401
|
+
"Luchador",
|
|
402
|
+
"Lynx",
|
|
403
|
+
"Maverick",
|
|
404
|
+
"Meteor",
|
|
405
|
+
"Monkey",
|
|
406
|
+
"Monsoon",
|
|
407
|
+
"Moose",
|
|
408
|
+
"Ninja",
|
|
409
|
+
"Nova",
|
|
410
|
+
"Octopus",
|
|
411
|
+
"Oracle",
|
|
412
|
+
"Otter",
|
|
413
|
+
"Panther",
|
|
414
|
+
"Phoenix",
|
|
415
|
+
"Pirate",
|
|
416
|
+
"Pixel",
|
|
417
|
+
"Puma",
|
|
418
|
+
"Quasar",
|
|
419
|
+
"Racer",
|
|
420
|
+
"Raptor",
|
|
421
|
+
"Raven",
|
|
422
|
+
"Reactor",
|
|
423
|
+
"Rocket",
|
|
424
|
+
"Ronin",
|
|
425
|
+
"Saber",
|
|
426
|
+
"Scorpion",
|
|
427
|
+
"Shark",
|
|
428
|
+
"Spartan",
|
|
429
|
+
"Sphinx",
|
|
430
|
+
"Sprinter",
|
|
431
|
+
"Stallion",
|
|
432
|
+
"Tiger",
|
|
433
|
+
"Titan",
|
|
434
|
+
"Viking",
|
|
435
|
+
"Viper",
|
|
436
|
+
"Wizard"
|
|
437
|
+
];
|
|
438
|
+
function generatePlayerName() {
|
|
439
|
+
const adjective = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
|
|
440
|
+
const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
|
|
441
|
+
const number = Math.floor(Math.random() * 99) + 1;
|
|
442
|
+
const base = (adjective + noun).slice(0, MAX_BASE_LENGTH);
|
|
443
|
+
return `${base}${number}`;
|
|
444
|
+
}
|
|
445
|
+
|
|
232
446
|
// src/PlayerIdentity.ts
|
|
233
447
|
var DEFAULT_KEY_PREFIX = "keeperboard_";
|
|
234
448
|
var PlayerIdentity = class {
|
|
@@ -236,6 +450,7 @@ var PlayerIdentity = class {
|
|
|
236
450
|
this.keyPrefix = config.keyPrefix ?? DEFAULT_KEY_PREFIX;
|
|
237
451
|
this.guidKey = `${this.keyPrefix}player_guid`;
|
|
238
452
|
this.nameKey = `${this.keyPrefix}player_name`;
|
|
453
|
+
this.nameAutoKey = `${this.keyPrefix}player_name_auto`;
|
|
239
454
|
}
|
|
240
455
|
/**
|
|
241
456
|
* Get the stored player GUID, or null if none exists.
|
|
@@ -284,6 +499,31 @@ var PlayerIdentity = class {
|
|
|
284
499
|
return;
|
|
285
500
|
}
|
|
286
501
|
localStorage.setItem(this.nameKey, name);
|
|
502
|
+
localStorage.removeItem(this.nameAutoKey);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Get the stored player name, creating an auto-generated one if it doesn't exist.
|
|
506
|
+
* Uses AdjectiveNounNumber pattern (e.g., ArcaneBlob99).
|
|
507
|
+
*/
|
|
508
|
+
getOrCreatePlayerName() {
|
|
509
|
+
let name = this.getPlayerName();
|
|
510
|
+
if (!name) {
|
|
511
|
+
name = generatePlayerName();
|
|
512
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
513
|
+
localStorage.setItem(this.nameKey, name);
|
|
514
|
+
localStorage.setItem(this.nameAutoKey, "true");
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return name;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Check if the current player name was auto-generated (vs explicitly set by user).
|
|
521
|
+
*/
|
|
522
|
+
isAutoGeneratedName() {
|
|
523
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
return localStorage.getItem(this.nameAutoKey) === "true";
|
|
287
527
|
}
|
|
288
528
|
/**
|
|
289
529
|
* Clear all stored player identity data.
|
|
@@ -294,6 +534,7 @@ var PlayerIdentity = class {
|
|
|
294
534
|
}
|
|
295
535
|
localStorage.removeItem(this.guidKey);
|
|
296
536
|
localStorage.removeItem(this.nameKey);
|
|
537
|
+
localStorage.removeItem(this.nameAutoKey);
|
|
297
538
|
}
|
|
298
539
|
/**
|
|
299
540
|
* Check if player identity is stored.
|
|
@@ -446,16 +687,12 @@ var RetryQueue = class {
|
|
|
446
687
|
var DEFAULTS = {
|
|
447
688
|
minLength: 2,
|
|
448
689
|
maxLength: 12,
|
|
449
|
-
|
|
450
|
-
allowedPattern: /[^A-Z0-9_]/g
|
|
690
|
+
allowedPattern: /[^A-Za-z0-9_]/g
|
|
451
691
|
};
|
|
452
692
|
function validateName(input, options) {
|
|
453
693
|
const opts = { ...DEFAULTS, ...options };
|
|
454
694
|
let name = input.trim();
|
|
455
|
-
|
|
456
|
-
name = name.toUpperCase();
|
|
457
|
-
}
|
|
458
|
-
const pattern = options?.allowedPattern ?? (opts.uppercase ? /[^A-Z0-9_]/g : /[^A-Za-z0-9_]/g);
|
|
695
|
+
const pattern = options?.allowedPattern ?? /[^A-Za-z0-9_]/g;
|
|
459
696
|
name = name.replace(pattern, "");
|
|
460
697
|
name = name.substring(0, opts.maxLength);
|
|
461
698
|
if (name.length < opts.minLength) {
|
|
@@ -477,7 +714,6 @@ var KeeperBoardSession = class {
|
|
|
477
714
|
});
|
|
478
715
|
this.identity = new PlayerIdentity(config.identity);
|
|
479
716
|
this.leaderboard = config.leaderboard;
|
|
480
|
-
this.defaultPlayerName = config.defaultPlayerName ?? "ANON";
|
|
481
717
|
this.cache = config.cache ? new Cache(config.cache.ttlMs) : null;
|
|
482
718
|
this.retryQueue = config.retry ? new RetryQueue(
|
|
483
719
|
`keeperboard_retry_${config.leaderboard}`,
|
|
@@ -491,14 +727,18 @@ var KeeperBoardSession = class {
|
|
|
491
727
|
getPlayerGuid() {
|
|
492
728
|
return this.identity.getOrCreatePlayerGuid();
|
|
493
729
|
}
|
|
494
|
-
/** Get the stored player name,
|
|
730
|
+
/** Get the stored player name, auto-generating one if none exists. */
|
|
495
731
|
getPlayerName() {
|
|
496
|
-
return this.identity.
|
|
732
|
+
return this.identity.getOrCreatePlayerName();
|
|
497
733
|
}
|
|
498
734
|
/** Store a player name locally. Does NOT update the server — call updatePlayerName() for that. */
|
|
499
735
|
setPlayerName(name) {
|
|
500
736
|
this.identity.setPlayerName(name);
|
|
501
737
|
}
|
|
738
|
+
/** Check if the player has explicitly set a name (vs auto-generated). */
|
|
739
|
+
hasExplicitPlayerName() {
|
|
740
|
+
return this.identity.getPlayerName() !== null && !this.identity.isAutoGeneratedName();
|
|
741
|
+
}
|
|
502
742
|
/** Validate a name using configurable rules. Returns sanitized string or null. */
|
|
503
743
|
validateName(input, options) {
|
|
504
744
|
return validateName(input, options);
|
|
@@ -647,5 +887,6 @@ export {
|
|
|
647
887
|
KeeperBoardSession,
|
|
648
888
|
PlayerIdentity,
|
|
649
889
|
RetryQueue,
|
|
890
|
+
generatePlayerName,
|
|
650
891
|
validateName
|
|
651
892
|
};
|