loredata 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +72 -21
  2. package/data/avengers/addresses.json +27 -0
  3. package/data/avengers/characters.json +178 -0
  4. package/data/avengers/meta.json +13 -0
  5. package/data/better-call-saul/addresses.json +37 -0
  6. package/data/better-call-saul/characters.json +156 -0
  7. package/data/better-call-saul/meta.json +13 -0
  8. package/data/big-bang-theory/addresses.json +31 -0
  9. package/data/big-bang-theory/characters.json +121 -0
  10. package/data/big-bang-theory/meta.json +13 -0
  11. package/data/breaking-bad/characters.json +49 -13
  12. package/data/breaking-bad/meta.json +10 -1
  13. package/data/fast-and-furious/characters.json +39 -13
  14. package/data/fast-and-furious/meta.json +15 -1
  15. package/data/friends/characters.json +138 -22
  16. package/data/friends/meta.json +13 -1
  17. package/data/game-of-thrones/characters.json +61 -16
  18. package/data/game-of-thrones/meta.json +10 -1
  19. package/data/guardians-of-the-galaxy/addresses.json +17 -0
  20. package/data/guardians-of-the-galaxy/characters.json +124 -0
  21. package/data/guardians-of-the-galaxy/meta.json +13 -0
  22. package/data/harry-potter/characters.json +37 -7
  23. package/data/harry-potter/meta.json +10 -1
  24. package/data/house-md/characters.json +79 -25
  25. package/data/house-md/meta.json +13 -1
  26. package/data/lost/characters.json +144 -36
  27. package/data/lost/meta.json +13 -1
  28. package/data/matrix/characters.json +133 -34
  29. package/data/matrix/meta.json +18 -1
  30. package/data/peaky-blinders/characters.json +44 -11
  31. package/data/peaky-blinders/meta.json +13 -1
  32. package/data/prison-break/addresses.json +24 -0
  33. package/data/prison-break/characters.json +116 -0
  34. package/data/prison-break/meta.json +13 -0
  35. package/data/sherlock/characters.json +116 -27
  36. package/data/sherlock/meta.json +13 -1
  37. package/data/simpsons/addresses.json +21 -0
  38. package/data/simpsons/characters.json +219 -0
  39. package/data/simpsons/meta.json +13 -0
  40. package/data/sopranos/addresses.json +37 -0
  41. package/data/sopranos/characters.json +184 -0
  42. package/data/sopranos/meta.json +13 -0
  43. package/data/south-park/addresses.json +31 -0
  44. package/data/south-park/characters.json +230 -0
  45. package/data/south-park/meta.json +13 -0
  46. package/data/spider-man/addresses.json +31 -0
  47. package/data/spider-man/characters.json +134 -0
  48. package/data/spider-man/meta.json +13 -0
  49. package/data/star-wars/addresses.json +19 -0
  50. package/data/star-wars/characters.json +153 -0
  51. package/data/star-wars/meta.json +13 -0
  52. package/data/supernatural/addresses.json +25 -0
  53. package/data/supernatural/characters.json +113 -0
  54. package/data/supernatural/meta.json +13 -0
  55. package/data/the-office/characters.json +84 -29
  56. package/data/the-office/meta.json +10 -1
  57. package/data/the-walking-dead/addresses.json +25 -0
  58. package/data/the-walking-dead/characters.json +114 -0
  59. package/data/the-walking-dead/meta.json +13 -0
  60. package/data/westworld/addresses.json +19 -0
  61. package/data/westworld/characters.json +108 -0
  62. package/data/westworld/meta.json +13 -0
  63. package/data/x-men/addresses.json +24 -0
  64. package/data/x-men/characters.json +158 -0
  65. package/data/x-men/meta.json +18 -0
  66. package/dist/browser.cjs +114 -69
  67. package/dist/browser.cjs.map +1 -1
  68. package/dist/browser.d.cts +7 -3
  69. package/dist/browser.d.ts +7 -3
  70. package/dist/browser.js +110 -69
  71. package/dist/browser.js.map +1 -1
  72. package/dist/cli/cli.cjs +131 -70
  73. package/dist/cli/cli.cjs.map +1 -1
  74. package/dist/cli/cli.js +132 -71
  75. package/dist/cli/cli.js.map +1 -1
  76. package/dist/index.cjs +132 -68
  77. package/dist/index.cjs.map +1 -1
  78. package/dist/index.d.cts +15 -4
  79. package/dist/index.d.ts +15 -4
  80. package/dist/index.js +132 -69
  81. package/dist/index.js.map +1 -1
  82. package/dist/{universe-store-DJrm7bP7.d.cts → universe-store-CWhCn3U6.d.cts} +31 -19
  83. package/dist/{universe-store-DJrm7bP7.d.ts → universe-store-CWhCn3U6.d.ts} +31 -19
  84. package/package.json +12 -4
  85. package/data/breaking-bad/domains.json +0 -6
  86. package/data/fast-and-furious/domains.json +0 -6
  87. package/data/friends/domains.json +0 -6
  88. package/data/game-of-thrones/domains.json +0 -6
  89. package/data/harry-potter/domains.json +0 -6
  90. package/data/house-md/domains.json +0 -6
  91. package/data/lost/domains.json +0 -6
  92. package/data/matrix/domains.json +0 -6
  93. package/data/peaky-blinders/domains.json +0 -6
  94. package/data/sherlock/domains.json +0 -6
  95. package/data/the-office/domains.json +0 -6
package/dist/cli/cli.js CHANGED
@@ -5,33 +5,105 @@ import { Command } from "commander";
5
5
 
6
6
  // src/universes/loader.ts
7
7
  import { readFileSync, readdirSync } from "fs";
8
- import { join } from "path";
9
- var dataDir = join(import.meta.dirname, "../data");
8
+ import { createRequire } from "module";
9
+ import { dirname, join } from "path";
10
+ var require2 = createRequire(import.meta.url);
11
+ var packageRoot = dirname(require2.resolve("loredata/package.json"));
12
+ var dataDir = join(packageRoot, "data");
10
13
  var UniverseLoader = class {
11
14
  static cache = /* @__PURE__ */ new Map();
12
15
  static register(data) {
13
16
  this.cache.set(data.id, data);
14
17
  }
15
18
  static load(universeId) {
16
- const cached = this.cache.get(universeId);
17
- if (cached) {
18
- return cached;
19
+ if (process.env.NODE_ENV !== "development") {
20
+ const cached = this.cache.get(universeId);
21
+ if (cached) {
22
+ return cached;
23
+ }
19
24
  }
20
25
  const universeDir = join(dataDir, universeId);
21
26
  const meta = JSON.parse(readFileSync(join(universeDir, "meta.json"), "utf-8"));
22
27
  const characters = JSON.parse(readFileSync(join(universeDir, "characters.json"), "utf-8"));
23
28
  const addresses = JSON.parse(readFileSync(join(universeDir, "addresses.json"), "utf-8"));
24
- const domains = JSON.parse(readFileSync(join(universeDir, "domains.json"), "utf-8"));
25
29
  const universeData = {
26
30
  id: meta.id,
27
31
  name: meta.name,
32
+ genre: meta.genre,
33
+ description: meta.description,
28
34
  characters,
29
35
  addresses,
30
- domains
36
+ ...meta.tmdbId !== void 0 && { tmdbId: meta.tmdbId },
37
+ ...meta.mediaType !== void 0 && { mediaType: meta.mediaType },
38
+ ...meta.rating !== void 0 && { rating: meta.rating },
39
+ ...meta.year !== void 0 && { year: meta.year },
40
+ ...meta.networks !== void 0 && { networks: meta.networks },
41
+ ...meta.posterPath !== void 0 && { posterPath: meta.posterPath },
42
+ ...meta.backdropPath !== void 0 && { backdropPath: meta.backdropPath }
31
43
  };
32
44
  this.cache.set(universeId, universeData);
33
45
  return universeData;
34
46
  }
47
+ static getManifest() {
48
+ const ids = this.listAvailable();
49
+ const result = ids.map((id) => {
50
+ const universeDir = join(dataDir, id);
51
+ return JSON.parse(readFileSync(join(universeDir, "meta.json"), "utf-8"));
52
+ });
53
+ return result;
54
+ }
55
+ static getAllInterests() {
56
+ const ids = this.listAvailable();
57
+ const interestSet = /* @__PURE__ */ new Set();
58
+ for (const id of ids) {
59
+ const universe = this.load(id);
60
+ for (const character of universe.characters) {
61
+ for (const interest of character.interests) {
62
+ interestSet.add(interest);
63
+ }
64
+ }
65
+ }
66
+ const result = Array.from(interestSet).sort();
67
+ return result;
68
+ }
69
+ static getAllLocations() {
70
+ const ids = this.listAvailable();
71
+ const seen = /* @__PURE__ */ new Map();
72
+ for (const id of ids) {
73
+ const universe = this.load(id);
74
+ for (const address of universe.addresses) {
75
+ if (address.city && !seen.has(`city:${address.city}`)) {
76
+ seen.set(`city:${address.city}`, { name: address.city, type: "city" });
77
+ }
78
+ if (address.state && !seen.has(`state:${address.state}`)) {
79
+ seen.set(`state:${address.state}`, { name: address.state, type: "state" });
80
+ }
81
+ if (address.country && !seen.has(`country:${address.country}`)) {
82
+ seen.set(`country:${address.country}`, { name: address.country, type: "country" });
83
+ }
84
+ }
85
+ }
86
+ return Array.from(seen.values()).sort((a, b) => a.name.localeCompare(b.name));
87
+ }
88
+ static buildCharacterIndex() {
89
+ const ids = this.listAvailable();
90
+ const entries = [];
91
+ for (const id of ids) {
92
+ const universe = this.load(id);
93
+ for (const character of universe.characters) {
94
+ entries.push({
95
+ characterId: character.id,
96
+ universeId: universe.id,
97
+ universeName: universe.name,
98
+ firstName: character.firstName ?? "",
99
+ lastName: character.lastName ?? "",
100
+ interests: character.interests,
101
+ profession: character.profession
102
+ });
103
+ }
104
+ }
105
+ return entries;
106
+ }
35
107
  static listAvailable() {
36
108
  const entries = readdirSync(dataDir, { withFileTypes: true });
37
109
  const ids = entries.filter((entry) => {
@@ -70,55 +142,12 @@ function pickRandom(array, rng) {
70
142
 
71
143
  // src/generators/email.ts
72
144
  var EmailGenerator = class {
73
- static generate(firstName, lastName, domains, rng) {
74
- const domain = pickRandom(domains.emailDomains, rng);
75
- const first = firstName.toLowerCase();
76
- const last = lastName.toLowerCase();
77
- return `${first}.${last}@${domain}`;
78
- }
79
- static generateFromUsername(username, domains, rng) {
80
- const domain = pickRandom(domains.emailDomains, rng);
145
+ static generateFromUsername(username, emailDomains, rng) {
146
+ const domain = pickRandom(emailDomains, rng);
81
147
  return `${username}@${domain}`;
82
148
  }
83
149
  };
84
150
 
85
- // src/generators/phone.ts
86
- var PhoneGenerator = class {
87
- static generate(domains, rng) {
88
- if (domains.phoneEasterEggs && domains.phoneEasterEggs.length > 0 && rng() < 0.2) {
89
- return pickRandom(domains.phoneEasterEggs, rng);
90
- }
91
- const prefix = pickRandom(domains.phonePrefixes, rng);
92
- const suffix = this.randomDigits(7, rng);
93
- return `${prefix}-${suffix.slice(0, 3)}-${suffix.slice(3)}`;
94
- }
95
- static randomDigits(count, rng) {
96
- let result = "";
97
- for (let i = 0; i < count; i++) {
98
- result += Math.floor(rng() * 10).toString();
99
- }
100
- return result;
101
- }
102
- };
103
-
104
- // src/generators/password.ts
105
- var PasswordGenerator = class {
106
- static generate(domains, rng) {
107
- if (domains.passwordEasterEggs && domains.passwordEasterEggs.length > 0 && rng() < 0.3) {
108
- return pickRandom(domains.passwordEasterEggs, rng);
109
- }
110
- return this.randomPassword(12, rng);
111
- }
112
- static randomPassword(length, rng) {
113
- const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$";
114
- let result = "";
115
- for (let i = 0; i < length; i++) {
116
- result += chars[Math.floor(rng() * chars.length)];
117
- }
118
- return result;
119
- }
120
- };
121
-
122
151
  // src/engine/person-factory.ts
123
152
  var PersonFactory = class {
124
153
  static build(universe, seed) {
@@ -134,16 +163,45 @@ var PersonFactory = class {
134
163
  const rng = createRng(seed);
135
164
  return this.buildFromCharacter(character, universe, rng);
136
165
  }
166
+ static buildCanonical(characterId, universe) {
167
+ const character = universe.characters.find((c) => c.id === characterId);
168
+ if (!character) {
169
+ throw new Error(`Character "${characterId}" not found in universe "${universe.id}"`);
170
+ }
171
+ const address = character.address ?? universe.addresses[0];
172
+ const username = character.usernames[0];
173
+ const rng = createRng(0);
174
+ const email = EmailGenerator.generateFromUsername(username, character.emailDomains, rng);
175
+ const quote = character.quotes[0];
176
+ const person = {
177
+ id: crypto.randomUUID(),
178
+ characterId: character.id,
179
+ firstName: character.firstName,
180
+ lastName: character.lastName,
181
+ username,
182
+ email,
183
+ address: {
184
+ street: address.street,
185
+ city: address.city,
186
+ state: address.state ?? "",
187
+ zip: address.zip ?? "",
188
+ country: address.country
189
+ },
190
+ profession: character.profession,
191
+ interests: character.interests,
192
+ quote,
193
+ universe: universe.id,
194
+ universeName: universe.name,
195
+ ...character.symbol ? { symbol: character.symbol } : {},
196
+ ...character.color ? { color: character.color } : {}
197
+ };
198
+ return person;
199
+ }
137
200
  static buildFromCharacter(character, universe, rng) {
138
201
  const address = character.address ?? pickRandom(universe.addresses, rng);
139
202
  const username = pickRandom(character.usernames, rng);
140
- const domains = character.emailDomain ? { ...universe.domains, emailDomains: [character.emailDomain] } : universe.domains;
141
- const email = EmailGenerator.generateFromUsername(username, domains, rng);
142
- const phone = PhoneGenerator.generate(universe.domains, rng);
143
- const password = PasswordGenerator.generate(universe.domains, rng);
203
+ const email = EmailGenerator.generateFromUsername(username, character.emailDomains, rng);
144
204
  const quote = pickRandom(character.quotes, rng);
145
- const avatarName = encodeURIComponent(`${character.firstName} ${character.lastName}`);
146
- const avatar = `https://ui-avatars.com/api/?name=${avatarName}&background=random`;
147
205
  const person = {
148
206
  id: crypto.randomUUID(),
149
207
  characterId: character.id,
@@ -151,8 +209,6 @@ var PersonFactory = class {
151
209
  lastName: character.lastName,
152
210
  username,
153
211
  email,
154
- password,
155
- phone,
156
212
  address: {
157
213
  street: address.street,
158
214
  city: address.city,
@@ -165,7 +221,8 @@ var PersonFactory = class {
165
221
  quote,
166
222
  universe: universe.id,
167
223
  universeName: universe.name,
168
- avatar
224
+ ...character.symbol ? { symbol: character.symbol } : {},
225
+ ...character.color ? { color: character.color } : {}
169
226
  };
170
227
  return person;
171
228
  }
@@ -192,12 +249,13 @@ var PersonaBuilder = class {
192
249
  const ids = UniverseLoader.listAvailable();
193
250
  const result = ids.map((id) => {
194
251
  const data = UniverseLoader.load(id);
195
- const info = {
252
+ const meta = {
196
253
  id,
197
254
  name: data.name,
198
- characterCount: data.characters.length
255
+ genre: data.genre,
256
+ description: data.description
199
257
  };
200
- return info;
258
+ return meta;
201
259
  });
202
260
  return result;
203
261
  }
@@ -226,11 +284,15 @@ var UniverseStore = class {
226
284
  return result;
227
285
  }
228
286
  getUniverses() {
229
- const result = this.universes.map((u) => ({
230
- id: u.id,
231
- name: u.name,
232
- characterCount: u.characters.length
233
- }));
287
+ const result = this.universes.map((u) => {
288
+ const meta = {
289
+ id: u.id,
290
+ name: u.name,
291
+ genre: u.genre,
292
+ description: u.description
293
+ };
294
+ return meta;
295
+ });
234
296
  return result;
235
297
  }
236
298
  findCharacters(query) {
@@ -337,7 +399,6 @@ program.command("person").description("Generate a single persona").option("-u, -
337
399
  `
338
400
  Name: ${result.firstName} ${result.lastName} (@${result.username})
339
401
  Email: ${result.email}
340
- Phone: ${result.phone}
341
402
  Address: ${[result.address.street, result.address.city, result.address.country].filter(Boolean).join(", ")}
342
403
  Profession: ${result.profession}
343
404
  Interests: ${result.interests.join(", ")}
@@ -381,7 +442,7 @@ program.command("universes").description("List available universes").option("-f,
381
442
  return;
382
443
  }
383
444
  for (const u of list) {
384
- console.log(` ${u.id.padEnd(20)} ${u.name} (${u.characterCount} characters)`);
445
+ console.log(` ${u.id.padEnd(20)} ${u.name}`);
385
446
  }
386
447
  });
387
448
  program.parse();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/cli.ts","../../src/universes/loader.ts","../../src/generators/random.ts","../../src/generators/email.ts","../../src/generators/phone.ts","../../src/generators/password.ts","../../src/engine/person-factory.ts","../../src/engine/persona-builder.ts","../../src/engine/universe-store.ts","../../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\n\nimport { universes, UniverseLoader, UniverseStore } from '@/index';\n\nimport type { CharacterQuery } from '@/types';\n\nconst program = new Command();\n\nprogram.name('loredata').description('Pop culture fake data generator').version('0.1.0');\n\nprogram\n\t.command('person')\n\t.description('Generate a single persona')\n\t.option('-u, --universe <id>', 'Universe ID (e.g. breaking-bad). Omit for all universes.')\n\t.option('-s, --seed <n>', 'Seed for deterministic generation')\n\t.option('-f, --format <fmt>', 'Output format: pretty | json', 'pretty')\n\t.option('--interests <list>', 'Comma-separated interests filter (e.g. chemistry,cooking)')\n\t.option('--interests-mode <mode>', 'Match mode: and | or (default: or)', 'or')\n\t.option('--name <query>', 'Search by character name')\n\t.action(\n\t\t(options: { universe?: string; seed?: string; format: string; interests?: string; interestsMode: string; name?: string }) => {\n\t\t\tconst seed = options.seed ? parseInt(options.seed, 10) : undefined;\n\t\t\tconst universeIds = options.universe ? [options.universe] : UniverseLoader.listAvailable();\n\t\t\tconst universesData = universeIds.map((id) => UniverseLoader.load(id));\n\t\t\tconst storeInstance = new UniverseStore(universesData);\n\n\t\t\tconst query: CharacterQuery = {\n\t\t\t\tuniverses: options.universe ? [options.universe] : [],\n\t\t\t\tinterests: options.interests ? options.interests.split(',').map((s) => s.trim()) : [],\n\t\t\t\tinterestsMode: options.interestsMode === 'and' ? 'and' : 'or',\n\t\t\t\tname: options.name\n\t\t\t};\n\n\t\t\tconst result = storeInstance.generatePersonas(query, 1, seed)[0];\n\n\t\t\tif (!result) {\n\t\t\t\tconsole.error('No characters match the given filters.');\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\tif (options.format === 'json') {\n\t\t\t\tconsole.log(JSON.stringify(result, null, 2));\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconsole.log(\n\t\t\t\t`\nName: ${result.firstName} ${result.lastName} (@${result.username})\nEmail: ${result.email}\nPhone: ${result.phone}\nAddress: ${[result.address.street, result.address.city, result.address.country].filter(Boolean).join(', ')}\nProfession: ${result.profession}\nInterests: ${result.interests.join(', ')}\nQuote: ${result.quote}\nUniverse: ${result.universe}\n `.trim()\n\t\t\t);\n\t\t}\n\t);\n\nprogram\n\t.command('group')\n\t.description('Generate multiple personas')\n\t.option('-u, --universe <id>', 'Universe ID (e.g. got). Omit for all universes.')\n\t.option('-n, --size <n>', 'Number of personas', '3')\n\t.option('-s, --seed <n>', 'Seed for deterministic generation')\n\t.option('-f, --format <fmt>', 'Output format: pretty | json', 'pretty')\n\t.option('--interests <list>', 'Comma-separated interests filter (e.g. chemistry,cooking)')\n\t.option('--interests-mode <mode>', 'Match mode: and | or (default: or)', 'or')\n\t.option('--name <query>', 'Search by character name')\n\t.action(\n\t\t(options: {\n\t\t\tuniverse?: string;\n\t\t\tsize: string;\n\t\t\tseed?: string;\n\t\t\tformat: string;\n\t\t\tinterests?: string;\n\t\t\tinterestsMode: string;\n\t\t\tname?: string;\n\t\t}) => {\n\t\t\tconst size = parseInt(options.size, 10);\n\t\t\tconst seed = options.seed ? parseInt(options.seed, 10) : undefined;\n\t\t\tconst universeIds = options.universe ? [options.universe] : UniverseLoader.listAvailable();\n\t\t\tconst universesData = universeIds.map((id) => UniverseLoader.load(id));\n\t\t\tconst storeInstance = new UniverseStore(universesData);\n\n\t\t\tconst query: CharacterQuery = {\n\t\t\t\tuniverses: options.universe ? [options.universe] : [],\n\t\t\t\tinterests: options.interests ? options.interests.split(',').map((s) => s.trim()) : [],\n\t\t\t\tinterestsMode: options.interestsMode === 'and' ? 'and' : 'or',\n\t\t\t\tname: options.name\n\t\t\t};\n\n\t\t\tconst result = storeInstance.generatePersonas(query, size, seed);\n\n\t\t\tif (result.length === 0) {\n\t\t\t\tconsole.error('No characters match the given filters.');\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\tif (options.format === 'json') {\n\t\t\t\tconsole.log(JSON.stringify(result, null, 2));\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (const p of result) {\n\t\t\t\tconsole.log(`${p.firstName} ${p.lastName} <${p.email}> — ${p.profession}`);\n\t\t\t}\n\t\t}\n\t);\n\nprogram\n\t.command('universes')\n\t.description('List available universes')\n\t.option('-f, --format <fmt>', 'Output format: pretty | json', 'pretty')\n\t.action((options: { format: string }) => {\n\t\tconst list = universes();\n\n\t\tif (options.format === 'json') {\n\t\t\tconsole.log(JSON.stringify(list, null, 2));\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const u of list) {\n\t\t\tconsole.log(` ${u.id.padEnd(20)} ${u.name} (${u.characterCount} characters)`);\n\t\t}\n\t});\n\nprogram.parse();\n","import { readFileSync, readdirSync } from 'fs';\nimport { join } from 'path';\n\nimport type { UniverseData, CharacterData, AddressData, DomainsData } from '@/types';\n\nconst dataDir = join(import.meta.dirname, '../data');\n\nexport class UniverseLoader {\n\tprivate static cache = new Map<string, UniverseData>();\n\n\tstatic register(data: UniverseData): void {\n\t\tthis.cache.set(data.id, data);\n\t}\n\n\tstatic load(universeId: string): UniverseData {\n\t\tconst cached = this.cache.get(universeId);\n\n\t\tif (cached) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tconst universeDir = join(dataDir, universeId);\n\t\tconst meta = JSON.parse(readFileSync(join(universeDir, 'meta.json'), 'utf-8')) as {\n\t\t\tid: string;\n\t\t\tname: string;\n\t\t};\n\n\t\tconst characters = JSON.parse(readFileSync(join(universeDir, 'characters.json'), 'utf-8')) as CharacterData[];\n\n\t\tconst addresses = JSON.parse(readFileSync(join(universeDir, 'addresses.json'), 'utf-8')) as AddressData[];\n\n\t\tconst domains = JSON.parse(readFileSync(join(universeDir, 'domains.json'), 'utf-8')) as DomainsData;\n\n\t\tconst universeData: UniverseData = {\n\t\t\tid: meta.id,\n\t\t\tname: meta.name,\n\t\t\tcharacters,\n\t\t\taddresses,\n\t\t\tdomains\n\t\t};\n\n\t\tthis.cache.set(universeId, universeData);\n\n\t\treturn universeData;\n\t}\n\n\tstatic listAvailable(): string[] {\n\t\tconst entries = readdirSync(dataDir, { withFileTypes: true });\n\n\t\tconst ids = entries\n\t\t\t.filter((entry) => {\n\t\t\t\tif (!entry.isDirectory()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\treadFileSync(join(dataDir, entry.name, 'meta.json'), 'utf-8');\n\n\t\t\t\t\treturn true;\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.map((entry) => entry.name);\n\n\t\treturn ids;\n\t}\n}\n","/**\n * Seeded pseudo-random number generator (mulberry32).\n * Returns a function that produces values in [0, 1).\n */\nexport function createRng(seed?: number): () => number {\n\tif (seed === undefined) {\n\t\treturn Math.random;\n\t}\n\n\tlet s = seed;\n\n\treturn function rng(): number {\n\t\ts += 0x6d2b79f5;\n\t\tlet z = s;\n\t\tz = Math.imul(z ^ (z >>> 15), z | 1);\n\t\tz ^= z + Math.imul(z ^ (z >>> 7), z | 61);\n\n\t\treturn ((z ^ (z >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\nexport function pickRandom<T>(array: T[], rng: () => number): T {\n\tconst index = Math.floor(rng() * array.length);\n\n\treturn array[index];\n}\n","import { pickRandom } from './random';\n\nimport type { DomainsData } from '@/types';\n\nexport class EmailGenerator {\n\tstatic generate(firstName: string, lastName: string, domains: DomainsData, rng: () => number): string {\n\t\tconst domain = pickRandom(domains.emailDomains, rng);\n\t\tconst first = firstName.toLowerCase();\n\t\tconst last = lastName.toLowerCase();\n\n\t\treturn `${first}.${last}@${domain}`;\n\t}\n\n\tstatic generateFromUsername(username: string, domains: DomainsData, rng: () => number): string {\n\t\tconst domain = pickRandom(domains.emailDomains, rng);\n\n\t\treturn `${username}@${domain}`;\n\t}\n}\n","import { pickRandom } from './random';\n\nimport type { DomainsData } from '@/types';\n\nexport class PhoneGenerator {\n\tstatic generate(domains: DomainsData, rng: () => number): string {\n\t\tif (domains.phoneEasterEggs && domains.phoneEasterEggs.length > 0 && rng() < 0.2) {\n\t\t\treturn pickRandom(domains.phoneEasterEggs, rng);\n\t\t}\n\n\t\tconst prefix = pickRandom(domains.phonePrefixes, rng);\n\t\tconst suffix = this.randomDigits(7, rng);\n\n\t\treturn `${prefix}-${suffix.slice(0, 3)}-${suffix.slice(3)}`;\n\t}\n\n\tprivate static randomDigits(count: number, rng: () => number): string {\n\t\tlet result = '';\n\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tresult += Math.floor(rng() * 10).toString();\n\t\t}\n\n\t\treturn result;\n\t}\n}\n","import { pickRandom } from './random';\n\nimport type { DomainsData } from '@/types';\n\nexport class PasswordGenerator {\n\tstatic generate(domains: DomainsData, rng: () => number): string {\n\t\tif (domains.passwordEasterEggs && domains.passwordEasterEggs.length > 0 && rng() < 0.3) {\n\t\t\treturn pickRandom(domains.passwordEasterEggs, rng);\n\t\t}\n\n\t\treturn this.randomPassword(12, rng);\n\t}\n\n\tprivate static randomPassword(length: number, rng: () => number): string {\n\t\tconst chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$';\n\t\tlet result = '';\n\n\t\tfor (let i = 0; i < length; i++) {\n\t\t\tresult += chars[Math.floor(rng() * chars.length)];\n\t\t}\n\n\t\treturn result;\n\t}\n}\n","import { createRng, pickRandom, EmailGenerator, PhoneGenerator, PasswordGenerator } from '@/generators';\n\nimport type { Person, UniverseData, CharacterData } from '@/types';\n\nexport class PersonFactory {\n\tstatic build(universe: UniverseData, seed?: number): Person {\n\t\tconst rng = createRng(seed);\n\n\t\tconst character = pickRandom(universe.characters, rng);\n\n\t\treturn this.buildFromCharacter(character, universe, rng);\n\t}\n\n\tstatic buildByCharacterId(characterId: string, universe: UniverseData, seed?: number): Person {\n\t\tconst character = universe.characters.find((c) => c.id === characterId);\n\n\t\tif (!character) {\n\t\t\tthrow new Error(`Character \"${characterId}\" not found in universe \"${universe.id}\"`);\n\t\t}\n\n\t\tconst rng = createRng(seed);\n\n\t\treturn this.buildFromCharacter(character, universe, rng);\n\t}\n\n\tprivate static buildFromCharacter(character: CharacterData, universe: UniverseData, rng: () => number): Person {\n\t\tconst address = character.address ?? pickRandom(universe.addresses, rng);\n\n\t\tconst username = pickRandom(character.usernames, rng);\n\n\t\tconst domains = character.emailDomain ? { ...universe.domains, emailDomains: [character.emailDomain] } : universe.domains;\n\n\t\tconst email = EmailGenerator.generateFromUsername(username, domains, rng);\n\t\tconst phone = PhoneGenerator.generate(universe.domains, rng);\n\t\tconst password = PasswordGenerator.generate(universe.domains, rng);\n\t\tconst quote = pickRandom(character.quotes, rng);\n\t\tconst avatarName = encodeURIComponent(`${character.firstName} ${character.lastName}`);\n\t\tconst avatar = `https://ui-avatars.com/api/?name=${avatarName}&background=random`;\n\n\t\tconst person: Person = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\tcharacterId: character.id,\n\t\t\tfirstName: character.firstName,\n\t\t\tlastName: character.lastName,\n\t\t\tusername,\n\t\t\temail,\n\t\t\tpassword,\n\t\t\tphone,\n\t\t\taddress: {\n\t\t\t\tstreet: address.street,\n\t\t\t\tcity: address.city,\n\t\t\t\tstate: address.state ?? '',\n\t\t\t\tzip: address.zip ?? '',\n\t\t\t\tcountry: address.country\n\t\t\t},\n\t\t\tprofession: character.profession,\n\t\t\tinterests: character.interests,\n\t\t\tquote,\n\t\t\tuniverse: universe.id,\n\t\t\tuniverseName: universe.name,\n\t\t\tavatar\n\t\t};\n\n\t\treturn person;\n\t}\n}\n","import { UniverseLoader } from '@/universes';\n\nimport { PersonFactory } from './person-factory';\n\nimport type { Person, PersonOptions, GroupOptions, UniverseInfo, UniverseData } from '@/types';\n\nexport class PersonaBuilder {\n\tstatic buildPersonFromData(universe: UniverseData, options: Omit<PersonOptions, 'universe'>): Person {\n\t\treturn PersonFactory.build(universe, options.seed);\n\t}\n\n\tstatic buildPerson(options: PersonOptions): Person {\n\t\tconst universe = UniverseLoader.load(options.universe);\n\n\t\treturn PersonFactory.build(universe, options.seed);\n\t}\n\n\tstatic buildGroup(options: GroupOptions): Person[] {\n\t\tconst persons: Person[] = [];\n\n\t\tfor (let i = 0; i < options.size; i++) {\n\t\t\tconst seed = options.seed !== undefined ? options.seed + i : undefined;\n\n\t\t\tpersons.push(this.buildPerson({ universe: options.universe, seed }));\n\t\t}\n\n\t\treturn persons;\n\t}\n\n\tstatic listUniverses(): UniverseInfo[] {\n\t\tconst ids = UniverseLoader.listAvailable();\n\n\t\tconst result: UniverseInfo[] = ids.map((id) => {\n\t\t\tconst data = UniverseLoader.load(id);\n\n\t\t\tconst info: UniverseInfo = {\n\t\t\t\tid,\n\t\t\t\tname: data.name,\n\t\t\t\tcharacterCount: data.characters.length\n\t\t\t};\n\n\t\t\treturn info;\n\t\t});\n\n\t\treturn result;\n\t}\n}\n","import { createRng } from '@/generators';\n\nimport { PersonFactory } from './person-factory';\n\nimport type { UniverseData, Person, CharacterEntry, CharacterQuery } from '@/types';\n\nexport class UniverseStore {\n\tprivate universes: UniverseData[];\n\tprivate characterIndex: CharacterEntry[];\n\n\tconstructor(universes: UniverseData[]) {\n\t\tthis.universes = universes;\n\t\tthis.characterIndex = this.buildIndex(universes);\n\t}\n\n\tget index(): CharacterEntry[] {\n\t\treturn this.characterIndex;\n\t}\n\n\tgetInterests(universeIds?: string[]): string[] {\n\t\tconst entries =\n\t\t\tuniverseIds && universeIds.length > 0\n\t\t\t\t? this.characterIndex.filter((e) => universeIds.includes(e.universeId))\n\t\t\t\t: this.characterIndex;\n\n\t\tconst interestSet = new Set<string>();\n\n\t\tfor (const entry of entries) {\n\t\t\tfor (const interest of entry.interests) {\n\t\t\t\tinterestSet.add(interest);\n\t\t\t}\n\t\t}\n\n\t\tconst result = Array.from(interestSet).sort();\n\n\t\treturn result;\n\t}\n\n\tgetUniverses(): { id: string; name: string; characterCount: number }[] {\n\t\tconst result = this.universes.map((u) => ({\n\t\t\tid: u.id,\n\t\t\tname: u.name,\n\t\t\tcharacterCount: u.characters.length\n\t\t}));\n\n\t\treturn result;\n\t}\n\n\tfindCharacters(query: CharacterQuery): CharacterEntry[] {\n\t\tlet entries = this.characterIndex;\n\n\t\tif (query.universes && query.universes.length > 0) {\n\t\t\tentries = entries.filter((e) => query.universes!.includes(e.universeId));\n\t\t}\n\n\t\tif (query.name && query.name.trim().length > 0) {\n\t\t\tconst needle = query.name.toLowerCase();\n\n\t\t\tentries = entries.filter((e) => {\n\t\t\t\tconst fullName = `${e.firstName} ${e.lastName}`.toLowerCase();\n\n\t\t\t\treturn fullName.includes(needle);\n\t\t\t});\n\t\t}\n\n\t\tif (query.interests && query.interests.length > 0) {\n\t\t\tconst mode = query.interestsMode ?? 'or';\n\n\t\t\tif (mode === 'and') {\n\t\t\t\tentries = entries.filter((e) => query.interests!.every((interest) => e.interests.includes(interest)));\n\t\t\t} else {\n\t\t\t\tentries = entries.filter((e) => query.interests!.some((interest) => e.interests.includes(interest)));\n\t\t\t}\n\t\t}\n\n\t\treturn entries;\n\t}\n\n\tpersonByCharacterId(characterId: string, seed?: number): Person {\n\t\tconst entry = this.characterIndex.find((e) => e.characterId === characterId);\n\n\t\tif (!entry) {\n\t\t\tthrow new Error(`Character \"${characterId}\" not found in store`);\n\t\t}\n\n\t\tconst universe = this.universes.find((u) => u.id === entry.universeId);\n\n\t\tif (!universe) {\n\t\t\tthrow new Error(`Universe \"${entry.universeId}\" not found in store`);\n\t\t}\n\n\t\treturn PersonFactory.buildByCharacterId(characterId, universe, seed);\n\t}\n\n\tgeneratePersonas(query: CharacterQuery, count: number, seed?: number): Person[] {\n\t\tconst matching = this.findCharacters(query);\n\n\t\tif (matching.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst rng = createRng(seed);\n\t\tconst actualCount = Math.min(count, matching.length);\n\n\t\tconst shuffled = [...matching].sort(() => rng() - 0.5);\n\t\tconst selected = shuffled.slice(0, actualCount);\n\t\tconst personas: Person[] = [];\n\n\t\tfor (let i = 0; i < selected.length; i++) {\n\t\t\tconst entry = selected[i];\n\t\t\tconst universe = this.universes.find((u) => u.id === entry.universeId)!;\n\t\t\tconst personSeed = seed !== undefined ? seed + i : undefined;\n\n\t\t\tpersonas.push(PersonFactory.buildByCharacterId(entry.characterId, universe, personSeed));\n\t\t}\n\n\t\treturn personas;\n\t}\n\n\tprivate buildIndex(universes: UniverseData[]): CharacterEntry[] {\n\t\tconst index: CharacterEntry[] = [];\n\n\t\tfor (const universe of universes) {\n\t\t\tfor (const character of universe.characters) {\n\t\t\t\tconst entry: CharacterEntry = {\n\t\t\t\t\tcharacterId: character.id,\n\t\t\t\t\tuniverseId: universe.id,\n\t\t\t\t\tuniverseName: universe.name,\n\t\t\t\t\tfirstName: character.firstName,\n\t\t\t\t\tlastName: character.lastName,\n\t\t\t\t\tinterests: character.interests,\n\t\t\t\t\tprofession: character.profession\n\t\t\t\t};\n\n\t\t\t\tindex.push(entry);\n\t\t\t}\n\t\t}\n\n\t\treturn index;\n\t}\n}\n","import { PersonaBuilder } from '@/engine';\n\nimport type { Person, UniverseInfo, PersonOptions, GroupOptions, UniverseData } from '@/types';\n\nexport function person(options: PersonOptions): Person {\n\treturn PersonaBuilder.buildPerson(options);\n}\n\nexport function personFromData(universe: UniverseData, seed?: number): Person {\n\treturn PersonaBuilder.buildPersonFromData(universe, { seed });\n}\n\nexport function group(options: GroupOptions): Person[] {\n\treturn PersonaBuilder.buildGroup(options);\n}\n\nexport function universes(): UniverseInfo[] {\n\treturn PersonaBuilder.listUniverses();\n}\n\nexport { UniverseLoader } from '@/universes';\nexport { UniverseStore } from '@/engine';\n\nexport type { Person, UniverseInfo, PersonOptions, GroupOptions } from '@/types';\nexport type { Address, UniverseData, CharacterData, AddressData, DomainsData } from '@/types';\nexport type { CharacterEntry, CharacterQuery } from '@/types';\n"],"mappings":"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","names":["universes"]}
1
+ {"version":3,"sources":["../../src/cli/cli.ts","../../src/universes/loader.ts","../../src/generators/random.ts","../../src/generators/email.ts","../../src/engine/person-factory.ts","../../src/engine/persona-builder.ts","../../src/engine/universe-store.ts","../../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\n\nimport { universes, UniverseLoader, UniverseStore } from '@/index';\n\nimport type { CharacterQuery } from '@/types';\n\nconst program = new Command();\n\nprogram.name('loredata').description('Pop culture fake data generator').version('0.1.0');\n\nprogram\n\t.command('person')\n\t.description('Generate a single persona')\n\t.option('-u, --universe <id>', 'Universe ID (e.g. breaking-bad). Omit for all universes.')\n\t.option('-s, --seed <n>', 'Seed for deterministic generation')\n\t.option('-f, --format <fmt>', 'Output format: pretty | json', 'pretty')\n\t.option('--interests <list>', 'Comma-separated interests filter (e.g. chemistry,cooking)')\n\t.option('--interests-mode <mode>', 'Match mode: and | or (default: or)', 'or')\n\t.option('--name <query>', 'Search by character name')\n\t.action(\n\t\t(options: { universe?: string; seed?: string; format: string; interests?: string; interestsMode: string; name?: string }) => {\n\t\t\tconst seed = options.seed ? parseInt(options.seed, 10) : undefined;\n\t\t\tconst universeIds = options.universe ? [options.universe] : UniverseLoader.listAvailable();\n\t\t\tconst universesData = universeIds.map((id) => UniverseLoader.load(id));\n\t\t\tconst storeInstance = new UniverseStore(universesData);\n\n\t\t\tconst query: CharacterQuery = {\n\t\t\t\tuniverses: options.universe ? [options.universe] : [],\n\t\t\t\tinterests: options.interests ? options.interests.split(',').map((s) => s.trim()) : [],\n\t\t\t\tinterestsMode: options.interestsMode === 'and' ? 'and' : 'or',\n\t\t\t\tname: options.name\n\t\t\t};\n\n\t\t\tconst result = storeInstance.generatePersonas(query, 1, seed)[0];\n\n\t\t\tif (!result) {\n\t\t\t\tconsole.error('No characters match the given filters.');\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\tif (options.format === 'json') {\n\t\t\t\tconsole.log(JSON.stringify(result, null, 2));\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconsole.log(\n\t\t\t\t`\nName: ${result.firstName} ${result.lastName} (@${result.username})\nEmail: ${result.email}\nAddress: ${[result.address.street, result.address.city, result.address.country].filter(Boolean).join(', ')}\nProfession: ${result.profession}\nInterests: ${result.interests.join(', ')}\nQuote: ${result.quote}\nUniverse: ${result.universe}\n `.trim()\n\t\t\t);\n\t\t}\n\t);\n\nprogram\n\t.command('group')\n\t.description('Generate multiple personas')\n\t.option('-u, --universe <id>', 'Universe ID (e.g. got). Omit for all universes.')\n\t.option('-n, --size <n>', 'Number of personas', '3')\n\t.option('-s, --seed <n>', 'Seed for deterministic generation')\n\t.option('-f, --format <fmt>', 'Output format: pretty | json', 'pretty')\n\t.option('--interests <list>', 'Comma-separated interests filter (e.g. chemistry,cooking)')\n\t.option('--interests-mode <mode>', 'Match mode: and | or (default: or)', 'or')\n\t.option('--name <query>', 'Search by character name')\n\t.action(\n\t\t(options: {\n\t\t\tuniverse?: string;\n\t\t\tsize: string;\n\t\t\tseed?: string;\n\t\t\tformat: string;\n\t\t\tinterests?: string;\n\t\t\tinterestsMode: string;\n\t\t\tname?: string;\n\t\t}) => {\n\t\t\tconst size = parseInt(options.size, 10);\n\t\t\tconst seed = options.seed ? parseInt(options.seed, 10) : undefined;\n\t\t\tconst universeIds = options.universe ? [options.universe] : UniverseLoader.listAvailable();\n\t\t\tconst universesData = universeIds.map((id) => UniverseLoader.load(id));\n\t\t\tconst storeInstance = new UniverseStore(universesData);\n\n\t\t\tconst query: CharacterQuery = {\n\t\t\t\tuniverses: options.universe ? [options.universe] : [],\n\t\t\t\tinterests: options.interests ? options.interests.split(',').map((s) => s.trim()) : [],\n\t\t\t\tinterestsMode: options.interestsMode === 'and' ? 'and' : 'or',\n\t\t\t\tname: options.name\n\t\t\t};\n\n\t\t\tconst result = storeInstance.generatePersonas(query, size, seed);\n\n\t\t\tif (result.length === 0) {\n\t\t\t\tconsole.error('No characters match the given filters.');\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\tif (options.format === 'json') {\n\t\t\t\tconsole.log(JSON.stringify(result, null, 2));\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (const p of result) {\n\t\t\t\tconsole.log(`${p.firstName} ${p.lastName} <${p.email}> — ${p.profession}`);\n\t\t\t}\n\t\t}\n\t);\n\nprogram\n\t.command('universes')\n\t.description('List available universes')\n\t.option('-f, --format <fmt>', 'Output format: pretty | json', 'pretty')\n\t.action((options: { format: string }) => {\n\t\tconst list = universes();\n\n\t\tif (options.format === 'json') {\n\t\t\tconsole.log(JSON.stringify(list, null, 2));\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const u of list) {\n\t\t\tconsole.log(` ${u.id.padEnd(20)} ${u.name}`);\n\t\t}\n\t});\n\nprogram.parse();\n","import { readFileSync, readdirSync } from 'fs';\nimport { createRequire } from 'module';\nimport { dirname, join } from 'path';\n\nimport type { UniverseData, UniverseMeta, CharacterData, AddressData, CharacterEntry, LocationEntry } from '@/types';\n\nconst require = createRequire(import.meta.url);\nconst packageRoot = dirname(require.resolve('loredata/package.json'));\nconst dataDir = join(packageRoot, 'data');\n\nexport class UniverseLoader {\n\tprivate static cache = new Map<string, UniverseData>();\n\n\tstatic register(data: UniverseData): void {\n\t\tthis.cache.set(data.id, data);\n\t}\n\n\tstatic load(universeId: string): UniverseData {\n\t\tif (process.env.NODE_ENV !== 'development') {\n\t\t\tconst cached = this.cache.get(universeId);\n\n\t\t\tif (cached) {\n\t\t\t\treturn cached;\n\t\t\t}\n\t\t}\n\n\t\tconst universeDir = join(dataDir, universeId);\n\t\tconst meta = JSON.parse(readFileSync(join(universeDir, 'meta.json'), 'utf-8')) as UniverseMeta;\n\n\t\tconst characters = JSON.parse(readFileSync(join(universeDir, 'characters.json'), 'utf-8')) as CharacterData[];\n\n\t\tconst addresses = JSON.parse(readFileSync(join(universeDir, 'addresses.json'), 'utf-8')) as AddressData[];\n\n\t\tconst universeData: UniverseData = {\n\t\t\tid: meta.id,\n\t\t\tname: meta.name,\n\t\t\tgenre: meta.genre,\n\t\t\tdescription: meta.description,\n\t\t\tcharacters,\n\t\t\taddresses,\n\t\t\t...(meta.tmdbId !== undefined && { tmdbId: meta.tmdbId }),\n\t\t\t...(meta.mediaType !== undefined && { mediaType: meta.mediaType }),\n\t\t\t...(meta.rating !== undefined && { rating: meta.rating }),\n\t\t\t...(meta.year !== undefined && { year: meta.year }),\n\t\t\t...(meta.networks !== undefined && { networks: meta.networks }),\n\t\t\t...(meta.posterPath !== undefined && { posterPath: meta.posterPath }),\n\t\t\t...(meta.backdropPath !== undefined && { backdropPath: meta.backdropPath })\n\t\t};\n\n\t\tthis.cache.set(universeId, universeData);\n\n\t\treturn universeData;\n\t}\n\n\tstatic getManifest(): UniverseMeta[] {\n\t\tconst ids = this.listAvailable();\n\n\t\tconst result = ids.map((id) => {\n\t\t\tconst universeDir = join(dataDir, id);\n\n\t\t\treturn JSON.parse(readFileSync(join(universeDir, 'meta.json'), 'utf-8')) as UniverseMeta;\n\t\t});\n\n\t\treturn result;\n\t}\n\n\tstatic getAllInterests(): string[] {\n\t\tconst ids = this.listAvailable();\n\t\tconst interestSet = new Set<string>();\n\n\t\tfor (const id of ids) {\n\t\t\tconst universe = this.load(id);\n\n\t\t\tfor (const character of universe.characters) {\n\t\t\t\tfor (const interest of character.interests) {\n\t\t\t\t\tinterestSet.add(interest);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst result = Array.from(interestSet).sort();\n\n\t\treturn result;\n\t}\n\n\tstatic getAllLocations(): LocationEntry[] {\n\t\tconst ids = this.listAvailable();\n\t\tconst seen = new Map<string, LocationEntry>();\n\n\t\tfor (const id of ids) {\n\t\t\tconst universe = this.load(id);\n\n\t\t\tfor (const address of universe.addresses) {\n\t\t\t\tif (address.city && !seen.has(`city:${address.city}`)) {\n\t\t\t\t\tseen.set(`city:${address.city}`, { name: address.city, type: 'city' });\n\t\t\t\t}\n\n\t\t\t\tif (address.state && !seen.has(`state:${address.state}`)) {\n\t\t\t\t\tseen.set(`state:${address.state}`, { name: address.state, type: 'state' });\n\t\t\t\t}\n\n\t\t\t\tif (address.country && !seen.has(`country:${address.country}`)) {\n\t\t\t\t\tseen.set(`country:${address.country}`, { name: address.country, type: 'country' });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Array.from(seen.values()).sort((a, b) => a.name.localeCompare(b.name));\n\t}\n\n\tstatic buildCharacterIndex(): CharacterEntry[] {\n\t\tconst ids = this.listAvailable();\n\t\tconst entries: CharacterEntry[] = [];\n\n\t\tfor (const id of ids) {\n\t\t\tconst universe = this.load(id);\n\n\t\t\tfor (const character of universe.characters) {\n\t\t\t\tentries.push({\n\t\t\t\t\tcharacterId: character.id,\n\t\t\t\t\tuniverseId: universe.id,\n\t\t\t\t\tuniverseName: universe.name,\n\t\t\t\t\tfirstName: character.firstName ?? '',\n\t\t\t\t\tlastName: character.lastName ?? '',\n\t\t\t\t\tinterests: character.interests,\n\t\t\t\t\tprofession: character.profession\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn entries;\n\t}\n\n\tstatic listAvailable(): string[] {\n\t\tconst entries = readdirSync(dataDir, { withFileTypes: true });\n\n\t\tconst ids = entries\n\t\t\t.filter((entry) => {\n\t\t\t\tif (!entry.isDirectory()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\treadFileSync(join(dataDir, entry.name, 'meta.json'), 'utf-8');\n\n\t\t\t\t\treturn true;\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.map((entry) => entry.name);\n\n\t\treturn ids;\n\t}\n}\n","/**\n * Seeded pseudo-random number generator (mulberry32).\n * Returns a function that produces values in [0, 1).\n */\nexport function createRng(seed?: number): () => number {\n\tif (seed === undefined) {\n\t\treturn Math.random;\n\t}\n\n\tlet s = seed;\n\n\treturn function rng(): number {\n\t\ts += 0x6d2b79f5;\n\t\tlet z = s;\n\t\tz = Math.imul(z ^ (z >>> 15), z | 1);\n\t\tz ^= z + Math.imul(z ^ (z >>> 7), z | 61);\n\n\t\treturn ((z ^ (z >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\nexport function pickRandom<T>(array: T[], rng: () => number): T {\n\tconst index = Math.floor(rng() * array.length);\n\n\treturn array[index];\n}\n","import { pickRandom } from './random';\n\nexport class EmailGenerator {\n\tstatic generateFromUsername(username: string, emailDomains: string[], rng: () => number): string {\n\t\tconst domain = pickRandom(emailDomains, rng);\n\n\t\treturn `${username}@${domain}`;\n\t}\n}\n","import { createRng, pickRandom, EmailGenerator } from '@/generators';\n\nimport type { Person, UniverseData, CharacterData } from '@/types';\n\nexport class PersonFactory {\n\tstatic build(universe: UniverseData, seed?: number): Person {\n\t\tconst rng = createRng(seed);\n\n\t\tconst character = pickRandom(universe.characters, rng);\n\n\t\treturn this.buildFromCharacter(character, universe, rng);\n\t}\n\n\tstatic buildByCharacterId(characterId: string, universe: UniverseData, seed?: number): Person {\n\t\tconst character = universe.characters.find((c) => c.id === characterId);\n\n\t\tif (!character) {\n\t\t\tthrow new Error(`Character \"${characterId}\" not found in universe \"${universe.id}\"`);\n\t\t}\n\n\t\tconst rng = createRng(seed);\n\n\t\treturn this.buildFromCharacter(character, universe, rng);\n\t}\n\n\tstatic buildCanonical(characterId: string, universe: UniverseData): Person {\n\t\tconst character = universe.characters.find((c) => c.id === characterId);\n\n\t\tif (!character) {\n\t\t\tthrow new Error(`Character \"${characterId}\" not found in universe \"${universe.id}\"`);\n\t\t}\n\n\t\tconst address = character.address ?? universe.addresses[0];\n\t\tconst username = character.usernames[0];\n\t\tconst rng = createRng(0);\n\t\tconst email = EmailGenerator.generateFromUsername(username, character.emailDomains, rng);\n\t\tconst quote = character.quotes[0];\n\n\t\tconst person: Person = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\tcharacterId: character.id,\n\t\t\tfirstName: character.firstName,\n\t\t\tlastName: character.lastName,\n\t\t\tusername,\n\t\t\temail,\n\t\t\taddress: {\n\t\t\t\tstreet: address.street,\n\t\t\t\tcity: address.city,\n\t\t\t\tstate: address.state ?? '',\n\t\t\t\tzip: address.zip ?? '',\n\t\t\t\tcountry: address.country\n\t\t\t},\n\t\t\tprofession: character.profession,\n\t\t\tinterests: character.interests,\n\t\t\tquote,\n\t\t\tuniverse: universe.id,\n\t\t\tuniverseName: universe.name,\n\t\t\t...(character.symbol ? { symbol: character.symbol } : {}),\n\t\t\t...(character.color ? { color: character.color } : {})\n\t\t};\n\n\t\treturn person;\n\t}\n\n\tprivate static buildFromCharacter(character: CharacterData, universe: UniverseData, rng: () => number): Person {\n\t\tconst address = character.address ?? pickRandom(universe.addresses, rng);\n\t\tconst username = pickRandom(character.usernames, rng);\n\t\tconst email = EmailGenerator.generateFromUsername(username, character.emailDomains, rng);\n\t\tconst quote = pickRandom(character.quotes, rng);\n\n\t\tconst person: Person = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\tcharacterId: character.id,\n\t\t\tfirstName: character.firstName,\n\t\t\tlastName: character.lastName,\n\t\t\tusername,\n\t\t\temail,\n\t\t\taddress: {\n\t\t\t\tstreet: address.street,\n\t\t\t\tcity: address.city,\n\t\t\t\tstate: address.state ?? '',\n\t\t\t\tzip: address.zip ?? '',\n\t\t\t\tcountry: address.country\n\t\t\t},\n\t\t\tprofession: character.profession,\n\t\t\tinterests: character.interests,\n\t\t\tquote,\n\t\t\tuniverse: universe.id,\n\t\t\tuniverseName: universe.name,\n\t\t\t...(character.symbol ? { symbol: character.symbol } : {}),\n\t\t\t...(character.color ? { color: character.color } : {})\n\t\t};\n\n\t\treturn person;\n\t}\n}\n","import { UniverseLoader } from '@/universes';\n\nimport { PersonFactory } from './person-factory';\n\nimport type { Person, PersonOptions, GroupOptions, UniverseMeta, UniverseData } from '@/types';\n\nexport class PersonaBuilder {\n\tstatic buildPersonFromData(universe: UniverseData, options: Omit<PersonOptions, 'universe'>): Person {\n\t\treturn PersonFactory.build(universe, options.seed);\n\t}\n\n\tstatic buildPerson(options: PersonOptions): Person {\n\t\tconst universe = UniverseLoader.load(options.universe);\n\n\t\treturn PersonFactory.build(universe, options.seed);\n\t}\n\n\tstatic buildGroup(options: GroupOptions): Person[] {\n\t\tconst persons: Person[] = [];\n\n\t\tfor (let i = 0; i < options.size; i++) {\n\t\t\tconst seed = options.seed !== undefined ? options.seed + i : undefined;\n\n\t\t\tpersons.push(this.buildPerson({ universe: options.universe, seed }));\n\t\t}\n\n\t\treturn persons;\n\t}\n\n\tstatic listUniverses(): UniverseMeta[] {\n\t\tconst ids = UniverseLoader.listAvailable();\n\n\t\tconst result: UniverseMeta[] = ids.map((id) => {\n\t\t\tconst data = UniverseLoader.load(id);\n\n\t\t\tconst meta: UniverseMeta = {\n\t\t\t\tid,\n\t\t\t\tname: data.name,\n\t\t\t\tgenre: data.genre,\n\t\t\t\tdescription: data.description\n\t\t\t};\n\n\t\t\treturn meta;\n\t\t});\n\n\t\treturn result;\n\t}\n}\n","import { createRng } from '@/generators';\n\nimport { PersonFactory } from './person-factory';\n\nimport type { UniverseData, UniverseMeta, Person, CharacterEntry, CharacterQuery } from '@/types';\n\nexport class UniverseStore {\n\tprivate universes: UniverseData[];\n\tprivate characterIndex: CharacterEntry[];\n\n\tconstructor(universes: UniverseData[]) {\n\t\tthis.universes = universes;\n\t\tthis.characterIndex = this.buildIndex(universes);\n\t}\n\n\tget index(): CharacterEntry[] {\n\t\treturn this.characterIndex;\n\t}\n\n\tgetInterests(universeIds?: string[]): string[] {\n\t\tconst entries =\n\t\t\tuniverseIds && universeIds.length > 0\n\t\t\t\t? this.characterIndex.filter((e) => universeIds.includes(e.universeId))\n\t\t\t\t: this.characterIndex;\n\n\t\tconst interestSet = new Set<string>();\n\n\t\tfor (const entry of entries) {\n\t\t\tfor (const interest of entry.interests) {\n\t\t\t\tinterestSet.add(interest);\n\t\t\t}\n\t\t}\n\n\t\tconst result = Array.from(interestSet).sort();\n\n\t\treturn result;\n\t}\n\n\tgetUniverses(): UniverseMeta[] {\n\t\tconst result = this.universes.map((u) => {\n\t\t\tconst meta: UniverseMeta = {\n\t\t\t\tid: u.id,\n\t\t\t\tname: u.name,\n\t\t\t\tgenre: u.genre,\n\t\t\t\tdescription: u.description\n\t\t\t};\n\n\t\t\treturn meta;\n\t\t});\n\n\t\treturn result;\n\t}\n\n\tfindCharacters(query: CharacterQuery): CharacterEntry[] {\n\t\tlet entries = this.characterIndex;\n\n\t\tif (query.universes && query.universes.length > 0) {\n\t\t\tentries = entries.filter((e) => query.universes!.includes(e.universeId));\n\t\t}\n\n\t\tif (query.name && query.name.trim().length > 0) {\n\t\t\tconst needle = query.name.toLowerCase();\n\n\t\t\tentries = entries.filter((e) => {\n\t\t\t\tconst fullName = `${e.firstName} ${e.lastName}`.toLowerCase();\n\n\t\t\t\treturn fullName.includes(needle);\n\t\t\t});\n\t\t}\n\n\t\tif (query.interests && query.interests.length > 0) {\n\t\t\tconst mode = query.interestsMode ?? 'or';\n\n\t\t\tif (mode === 'and') {\n\t\t\t\tentries = entries.filter((e) => query.interests!.every((interest) => e.interests.includes(interest)));\n\t\t\t} else {\n\t\t\t\tentries = entries.filter((e) => query.interests!.some((interest) => e.interests.includes(interest)));\n\t\t\t}\n\t\t}\n\n\t\treturn entries;\n\t}\n\n\tpersonByCharacterId(characterId: string, seed?: number): Person {\n\t\tconst entry = this.characterIndex.find((e) => e.characterId === characterId);\n\n\t\tif (!entry) {\n\t\t\tthrow new Error(`Character \"${characterId}\" not found in store`);\n\t\t}\n\n\t\tconst universe = this.universes.find((u) => u.id === entry.universeId);\n\n\t\tif (!universe) {\n\t\t\tthrow new Error(`Universe \"${entry.universeId}\" not found in store`);\n\t\t}\n\n\t\treturn PersonFactory.buildByCharacterId(characterId, universe, seed);\n\t}\n\n\tgeneratePersonas(query: CharacterQuery, count: number, seed?: number): Person[] {\n\t\tconst matching = this.findCharacters(query);\n\n\t\tif (matching.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst rng = createRng(seed);\n\t\tconst actualCount = Math.min(count, matching.length);\n\n\t\tconst shuffled = [...matching].sort(() => rng() - 0.5);\n\t\tconst selected = shuffled.slice(0, actualCount);\n\t\tconst personas: Person[] = [];\n\n\t\tfor (let i = 0; i < selected.length; i++) {\n\t\t\tconst entry = selected[i];\n\t\t\tconst universe = this.universes.find((u) => u.id === entry.universeId)!;\n\t\t\tconst personSeed = seed !== undefined ? seed + i : undefined;\n\n\t\t\tpersonas.push(PersonFactory.buildByCharacterId(entry.characterId, universe, personSeed));\n\t\t}\n\n\t\treturn personas;\n\t}\n\n\tprivate buildIndex(universes: UniverseData[]): CharacterEntry[] {\n\t\tconst index: CharacterEntry[] = [];\n\n\t\tfor (const universe of universes) {\n\t\t\tfor (const character of universe.characters) {\n\t\t\t\tconst entry: CharacterEntry = {\n\t\t\t\t\tcharacterId: character.id,\n\t\t\t\t\tuniverseId: universe.id,\n\t\t\t\t\tuniverseName: universe.name,\n\t\t\t\t\tfirstName: character.firstName,\n\t\t\t\t\tlastName: character.lastName,\n\t\t\t\t\tinterests: character.interests,\n\t\t\t\t\tprofession: character.profession\n\t\t\t\t};\n\n\t\t\t\tindex.push(entry);\n\t\t\t}\n\t\t}\n\n\t\treturn index;\n\t}\n}\n","import { PersonaBuilder } from '@/engine';\n\nimport type { Person, UniverseMeta, PersonOptions, GroupOptions, UniverseData } from '@/types';\n\nexport function person(options: PersonOptions): Person {\n\treturn PersonaBuilder.buildPerson(options);\n}\n\nexport function personFromData(universe: UniverseData, seed?: number): Person {\n\treturn PersonaBuilder.buildPersonFromData(universe, { seed });\n}\n\nexport function group(options: GroupOptions): Person[] {\n\treturn PersonaBuilder.buildGroup(options);\n}\n\nexport function universes(): UniverseMeta[] {\n\treturn PersonaBuilder.listUniverses();\n}\n\nexport { UniverseLoader } from '@/universes';\nexport { UniverseStore, PersonFactory } from '@/engine';\n\nexport type { Person, UniverseMeta, PersonOptions, GroupOptions } from '@/types';\nexport type { Address, UniverseData, CharacterData, AddressData } from '@/types';\nexport type { CharacterEntry, CharacterQuery, LocationEntry, LocationType } from '@/types';\n"],"mappings":"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","names":["require","universes"]}