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 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;
@@ -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, falling back to defaultPlayerName. */
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. Optionally converts to uppercase (default: yes)
419
- * 3. Strips characters not matching `allowedPattern`
420
- * 4. Truncates to `maxLength`
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! ') // 'ACE_PILOT' → wait, no spaces allowed → 'ACEPILOT'
425
- * validateName('ab') // '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, falling back to defaultPlayerName. */
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. Optionally converts to uppercase (default: yes)
419
- * 3. Strips characters not matching `allowedPattern`
420
- * 4. Truncates to `maxLength`
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! ') // 'ACE_PILOT' → wait, no spaces allowed → 'ACEPILOT'
425
- * validateName('ab') // '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
- uppercase: true,
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
- if (opts.uppercase) {
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, falling back to defaultPlayerName. */
763
+ /** Get the stored player name, auto-generating one if none exists. */
527
764
  getPlayerName() {
528
- return this.identity.getPlayerName() ?? this.defaultPlayerName;
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
- uppercase: true,
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
- if (opts.uppercase) {
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, falling back to defaultPlayerName. */
730
+ /** Get the stored player name, auto-generating one if none exists. */
495
731
  getPlayerName() {
496
- return this.identity.getPlayerName() ?? this.defaultPlayerName;
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keeperboard",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "TypeScript client SDK for KeeperBoard leaderboard-as-a-service",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",