keeperboard 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -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 or default
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;
@@ -303,7 +301,6 @@ declare class KeeperBoardSession {
303
301
  private readonly client;
304
302
  private readonly identity;
305
303
  private readonly leaderboard;
306
- private readonly defaultPlayerName;
307
304
  private readonly cache;
308
305
  private readonly retryQueue;
309
306
  private cachedLimit;
@@ -311,10 +308,12 @@ declare class KeeperBoardSession {
311
308
  constructor(config: SessionConfig);
312
309
  /** Get or create a persistent player GUID. */
313
310
  getPlayerGuid(): string;
314
- /** Get the stored player name, falling back to defaultPlayerName. */
311
+ /** Get the stored player name, auto-generating one if none exists. */
315
312
  getPlayerName(): string;
316
313
  /** Store a player name locally. Does NOT update the server — call updatePlayerName() for that. */
317
314
  setPlayerName(name: string): void;
315
+ /** Check if the player has explicitly set a name (vs auto-generated). */
316
+ hasExplicitPlayerName(): boolean;
318
317
  /** Validate a name using configurable rules. Returns sanitized string or null. */
319
318
  validateName(input: string, options?: NameValidationOptions): string | null;
320
319
  /**
@@ -369,6 +368,7 @@ declare class PlayerIdentity {
369
368
  private readonly keyPrefix;
370
369
  private readonly guidKey;
371
370
  private readonly nameKey;
371
+ private readonly nameAutoKey;
372
372
  constructor(config?: PlayerIdentityConfig);
373
373
  /**
374
374
  * Get the stored player GUID, or null if none exists.
@@ -391,6 +391,15 @@ declare class PlayerIdentity {
391
391
  * Set the player name in localStorage.
392
392
  */
393
393
  setPlayerName(name: string): void;
394
+ /**
395
+ * Get the stored player name, creating an auto-generated one if it doesn't exist.
396
+ * Uses AdjectiveNounNumber pattern (e.g., ArcaneBlob99).
397
+ */
398
+ getOrCreatePlayerName(): string;
399
+ /**
400
+ * Check if the current player name was auto-generated (vs explicitly set by user).
401
+ */
402
+ isAutoGeneratedName(): boolean;
394
403
  /**
395
404
  * Clear all stored player identity data.
396
405
  */
@@ -427,6 +436,22 @@ declare class PlayerIdentity {
427
436
  */
428
437
  declare function validateName(input: string, options?: NameValidationOptions): string | null;
429
438
 
439
+ /**
440
+ * Auto-generated player name system.
441
+ * Generates random AdjectiveNounNumber names (e.g., ArcaneBlob99).
442
+ * Names are PascalCase words plus a numeric suffix, and fit within 4-12 characters.
443
+ */
444
+ /**
445
+ * Generate a random player name in the format AdjectiveNoun1-99.
446
+ * Returns a PascalCase string with length 4-12 characters (fits validateName rules).
447
+ * ~990,000 unique combinations possible.
448
+ *
449
+ * @example
450
+ * generatePlayerName() // 'ArcaneBlob99'
451
+ * generatePlayerName() // 'CosmicViper42'
452
+ */
453
+ declare function generatePlayerName(): string;
454
+
430
455
  /**
431
456
  * Generic TTL cache with in-flight deduplication and background refresh.
432
457
  *
@@ -488,4 +513,4 @@ declare class RetryQueue {
488
513
  clear(): void;
489
514
  }
490
515
 
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 };
516
+ 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;
@@ -303,7 +301,6 @@ declare class KeeperBoardSession {
303
301
  private readonly client;
304
302
  private readonly identity;
305
303
  private readonly leaderboard;
306
- private readonly defaultPlayerName;
307
304
  private readonly cache;
308
305
  private readonly retryQueue;
309
306
  private cachedLimit;
@@ -311,10 +308,12 @@ declare class KeeperBoardSession {
311
308
  constructor(config: SessionConfig);
312
309
  /** Get or create a persistent player GUID. */
313
310
  getPlayerGuid(): string;
314
- /** Get the stored player name, falling back to defaultPlayerName. */
311
+ /** Get the stored player name, auto-generating one if none exists. */
315
312
  getPlayerName(): string;
316
313
  /** Store a player name locally. Does NOT update the server — call updatePlayerName() for that. */
317
314
  setPlayerName(name: string): void;
315
+ /** Check if the player has explicitly set a name (vs auto-generated). */
316
+ hasExplicitPlayerName(): boolean;
318
317
  /** Validate a name using configurable rules. Returns sanitized string or null. */
319
318
  validateName(input: string, options?: NameValidationOptions): string | null;
320
319
  /**
@@ -369,6 +368,7 @@ declare class PlayerIdentity {
369
368
  private readonly keyPrefix;
370
369
  private readonly guidKey;
371
370
  private readonly nameKey;
371
+ private readonly nameAutoKey;
372
372
  constructor(config?: PlayerIdentityConfig);
373
373
  /**
374
374
  * Get the stored player GUID, or null if none exists.
@@ -391,6 +391,15 @@ declare class PlayerIdentity {
391
391
  * Set the player name in localStorage.
392
392
  */
393
393
  setPlayerName(name: string): void;
394
+ /**
395
+ * Get the stored player name, creating an auto-generated one if it doesn't exist.
396
+ * Uses AdjectiveNounNumber pattern (e.g., ArcaneBlob99).
397
+ */
398
+ getOrCreatePlayerName(): string;
399
+ /**
400
+ * Check if the current player name was auto-generated (vs explicitly set by user).
401
+ */
402
+ isAutoGeneratedName(): boolean;
394
403
  /**
395
404
  * Clear all stored player identity data.
396
405
  */
@@ -427,6 +436,22 @@ declare class PlayerIdentity {
427
436
  */
428
437
  declare function validateName(input: string, options?: NameValidationOptions): string | null;
429
438
 
439
+ /**
440
+ * Auto-generated player name system.
441
+ * Generates random AdjectiveNounNumber names (e.g., ArcaneBlob99).
442
+ * Names are PascalCase words plus a numeric suffix, and fit within 4-12 characters.
443
+ */
444
+ /**
445
+ * Generate a random player name in the format AdjectiveNoun1-99.
446
+ * Returns a PascalCase string with length 4-12 characters (fits validateName rules).
447
+ * ~990,000 unique combinations possible.
448
+ *
449
+ * @example
450
+ * generatePlayerName() // 'ArcaneBlob99'
451
+ * generatePlayerName() // 'CosmicViper42'
452
+ */
453
+ declare function generatePlayerName(): string;
454
+
430
455
  /**
431
456
  * Generic TTL cache with in-flight deduplication and background refresh.
432
457
  *
@@ -488,4 +513,4 @@ declare class RetryQueue {
488
513
  clear(): void;
489
514
  }
490
515
 
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 };
516
+ 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.
@@ -509,7 +751,6 @@ var KeeperBoardSession = class {
509
751
  });
510
752
  this.identity = new PlayerIdentity(config.identity);
511
753
  this.leaderboard = config.leaderboard;
512
- this.defaultPlayerName = config.defaultPlayerName ?? "ANON";
513
754
  this.cache = config.cache ? new Cache(config.cache.ttlMs) : null;
514
755
  this.retryQueue = config.retry ? new RetryQueue(
515
756
  `keeperboard_retry_${config.leaderboard}`,
@@ -523,14 +764,18 @@ var KeeperBoardSession = class {
523
764
  getPlayerGuid() {
524
765
  return this.identity.getOrCreatePlayerGuid();
525
766
  }
526
- /** Get the stored player name, falling back to defaultPlayerName. */
767
+ /** Get the stored player name, auto-generating one if none exists. */
527
768
  getPlayerName() {
528
- return this.identity.getPlayerName() ?? this.defaultPlayerName;
769
+ return this.identity.getOrCreatePlayerName();
529
770
  }
530
771
  /** Store a player name locally. Does NOT update the server — call updatePlayerName() for that. */
531
772
  setPlayerName(name) {
532
773
  this.identity.setPlayerName(name);
533
774
  }
775
+ /** Check if the player has explicitly set a name (vs auto-generated). */
776
+ hasExplicitPlayerName() {
777
+ return this.identity.getPlayerName() !== null && !this.identity.isAutoGeneratedName();
778
+ }
534
779
  /** Validate a name using configurable rules. Returns sanitized string or null. */
535
780
  validateName(input, options) {
536
781
  return validateName(input, options);
@@ -680,5 +925,6 @@ var KeeperBoardSession = class {
680
925
  KeeperBoardSession,
681
926
  PlayerIdentity,
682
927
  RetryQueue,
928
+ generatePlayerName,
683
929
  validateName
684
930
  });
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.
@@ -477,7 +718,6 @@ var KeeperBoardSession = class {
477
718
  });
478
719
  this.identity = new PlayerIdentity(config.identity);
479
720
  this.leaderboard = config.leaderboard;
480
- this.defaultPlayerName = config.defaultPlayerName ?? "ANON";
481
721
  this.cache = config.cache ? new Cache(config.cache.ttlMs) : null;
482
722
  this.retryQueue = config.retry ? new RetryQueue(
483
723
  `keeperboard_retry_${config.leaderboard}`,
@@ -491,14 +731,18 @@ var KeeperBoardSession = class {
491
731
  getPlayerGuid() {
492
732
  return this.identity.getOrCreatePlayerGuid();
493
733
  }
494
- /** Get the stored player name, falling back to defaultPlayerName. */
734
+ /** Get the stored player name, auto-generating one if none exists. */
495
735
  getPlayerName() {
496
- return this.identity.getPlayerName() ?? this.defaultPlayerName;
736
+ return this.identity.getOrCreatePlayerName();
497
737
  }
498
738
  /** Store a player name locally. Does NOT update the server — call updatePlayerName() for that. */
499
739
  setPlayerName(name) {
500
740
  this.identity.setPlayerName(name);
501
741
  }
742
+ /** Check if the player has explicitly set a name (vs auto-generated). */
743
+ hasExplicitPlayerName() {
744
+ return this.identity.getPlayerName() !== null && !this.identity.isAutoGeneratedName();
745
+ }
502
746
  /** Validate a name using configurable rules. Returns sanitized string or null. */
503
747
  validateName(input, options) {
504
748
  return validateName(input, options);
@@ -647,5 +891,6 @@ export {
647
891
  KeeperBoardSession,
648
892
  PlayerIdentity,
649
893
  RetryQueue,
894
+ generatePlayerName,
650
895
  validateName
651
896
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keeperboard",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "TypeScript client SDK for KeeperBoard leaderboard-as-a-service",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",