this repo has no description
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add basic linking

+1427 -3
+68 -2
src/features/handler/linking.ts
··· 1 - import { slackApp } from "../../index"; 1 + import { eq } from "drizzle-orm"; 2 + import { db, slackApp } from "../../index"; 3 + import { users as usersTable } from "../../libs/schema"; 4 + import { generatePassphrase } from "../../libs/words"; 5 + import { getUser } from "../../libs/hackernews"; 2 6 3 7 export async function linkUserSetup() { 4 8 try { ··· 6 10 "/hn-alerts-link", 7 11 () => Promise.resolve(), 8 12 async ({ payload, context }) => { 13 + const userInput = payload.text?.trim() || null; 14 + let hnUsername = userInput; 15 + 16 + const userFromDB = await db 17 + .select() 18 + .from(usersTable) 19 + .where(eq(usersTable.id, payload.user_id)) 20 + .then((user) => user[0]); 21 + 22 + if (userFromDB) { 23 + if (!userFromDB.verified) { 24 + const res = await getUser( 25 + userFromDB.hackernewsUsername as string, 26 + ).then((user) => 27 + user?.about?.includes(userFromDB.challenge as string), 28 + ); 29 + 30 + if (!res) { 31 + await context.respond({ 32 + text: `Your Hacker News account is not verified. Add \`${userFromDB.challenge}\` to your <https://news.ycombinator.com/user?id=${userFromDB.hackernewsUsername}|profile>.`, 33 + response_type: "ephemeral", 34 + }); 35 + return; 36 + } 37 + 38 + await db.update(usersTable).set({ verified: true }); 39 + 40 + await context.respond({ 41 + text: "Your Hacker News account has been verified :yay:", 42 + response_type: "ephemeral", 43 + }); 44 + return; 45 + } 46 + 47 + await context.respond({ 48 + text: "You are already linked to a Hacker News account.", 49 + response_type: "ephemeral", 50 + }); 51 + return; 52 + } 53 + 54 + // Extract username from URL if provided 55 + if (userInput?.includes("news.ycombinator.com/user?id=")) { 56 + try { 57 + const cleanedInput = userInput.replace(/[<>]/g, ""); 58 + const username = new URL(cleanedInput).searchParams.get("id"); 59 + if (username) hnUsername = username; 60 + } catch (e) { 61 + console.log("Failed to parse URL, using raw input", e); 62 + } 63 + } 64 + 65 + const verificationPhrase = generatePassphrase(3); 66 + 67 + await db.insert(usersTable).values({ 68 + id: payload.user_id, 69 + hackernewsUsername: hnUsername, 70 + challenge: verificationPhrase, 71 + }); 72 + 9 73 await context.respond({ 10 - text: "Linking successful!", 74 + text: hnUsername 75 + ? `Please verify your Hacker News username: <https://news.ycombinator.com/user?id=${hnUsername}|\`${hnUsername}\`> by adding the verification phrase: \`${verificationPhrase}\`. When you're done, type \`/hn-alerts-link\` to complete the process.` 76 + : "Please provide your Hacker News username: `/hn-alerts-link your_username`", 11 77 response_type: "ephemeral", 12 78 }); 13 79 },
+46
src/libs/hackernews.ts
··· 1 + export interface User { 2 + id: string; 3 + created: number; 4 + karma: number; 5 + about?: string; 6 + submitted?: number[]; 7 + } 8 + 9 + /** 10 + * Fetches user data by user ID from the Hacker News API. 11 + * Only users with public activity (comments or story submissions) are available. 12 + * 13 + * @param userId - The user's unique username (case-sensitive) 14 + * @returns Promise resolving to the user data 15 + * @throws Error if the user cannot be found or if there's a network error 16 + */ 17 + export async function getUser(userId: string): Promise<User> { 18 + if (!userId) { 19 + throw new Error("User ID is required"); 20 + } 21 + 22 + try { 23 + const response = await fetch( 24 + `https://hacker-news.firebaseio.com/v0/user/${userId}.json`, 25 + ); 26 + 27 + if (!response.ok) { 28 + throw new Error( 29 + `Failed to fetch user with ID ${userId}: ${response.statusText}`, 30 + ); 31 + } 32 + 33 + const userData = await response.json(); 34 + 35 + if (!userData) { 36 + throw new Error(`User with ID ${userId} not found`); 37 + } 38 + 39 + return userData as User; 40 + } catch (error) { 41 + if (error instanceof Error) { 42 + throw error; 43 + } 44 + throw new Error(`Failed to fetch user with ID ${userId}: ${String(error)}`); 45 + } 46 + }
+3 -1
src/libs/schema.ts
··· 1 - import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; 1 + import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; 2 2 import type { Pool } from "pg"; 3 3 4 4 // Define the users table 5 5 export const users = pgTable("users", { 6 6 id: text("id").primaryKey(), 7 7 hackernewsUsername: text("hackernews_username"), 8 + challenge: text("challenge"), 9 + verified: boolean("verified").default(false), 8 10 createdAt: timestamp("created_at") 9 11 .$defaultFn(() => new Date()) 10 12 .notNull(),
+1310
src/libs/words.ts
··· 1 + const words: string[] = [ 2 + "aardvark", 3 + "abandoned", 4 + "abbreviate", 5 + "abdomen", 6 + "abhorrence", 7 + "abiding", 8 + "abnormal", 9 + "abrasion", 10 + "absorbing", 11 + "abundant", 12 + "abyss", 13 + "academy", 14 + "accountant", 15 + "acetone", 16 + "achiness", 17 + "acid", 18 + "acoustics", 19 + "acquire", 20 + "acrobat", 21 + "actress", 22 + "acuteness", 23 + "aerosol", 24 + "aesthetic", 25 + "affidavit", 26 + "afloat", 27 + "afraid", 28 + "aftershave", 29 + "again", 30 + "agency", 31 + "aggressor", 32 + "aghast", 33 + "agitate", 34 + "agnostic", 35 + "agonizing", 36 + "agreeing", 37 + "aidless", 38 + "aimlessly", 39 + "ajar", 40 + "alarmclock", 41 + "albatross", 42 + "alchemy", 43 + "alfalfa", 44 + "algae", 45 + "aliens", 46 + "alkaline", 47 + "almanac", 48 + "alongside", 49 + "alphabet", 50 + "already", 51 + "also", 52 + "altitude", 53 + "aluminum", 54 + "always", 55 + "amazingly", 56 + "ambulance", 57 + "amendment", 58 + "amiable", 59 + "ammunition", 60 + "amnesty", 61 + "amoeba", 62 + "amplifier", 63 + "amuser", 64 + "anagram", 65 + "anchor", 66 + "android", 67 + "anesthesia", 68 + "angelfish", 69 + "animal", 70 + "anklet", 71 + "announcer", 72 + "anonymous", 73 + "answer", 74 + "antelope", 75 + "anxiety", 76 + "anyplace", 77 + "aorta", 78 + "apartment", 79 + "apnea", 80 + "apostrophe", 81 + "apple", 82 + "apricot", 83 + "aquamarine", 84 + "arachnid", 85 + "arbitrate", 86 + "ardently", 87 + "arena", 88 + "argument", 89 + "aristocrat", 90 + "armchair", 91 + "aromatic", 92 + "arrowhead", 93 + "arsonist", 94 + "artichoke", 95 + "asbestos", 96 + "ascend", 97 + "aseptic", 98 + "ashamed", 99 + "asinine", 100 + "asleep", 101 + "asocial", 102 + "asparagus", 103 + "astronaut", 104 + "asymmetric", 105 + "atlas", 106 + "atmosphere", 107 + "atom", 108 + "atrocious", 109 + "attic", 110 + "atypical", 111 + "auctioneer", 112 + "auditorium", 113 + "augmented", 114 + "auspicious", 115 + "automobile", 116 + "auxiliary", 117 + "avalanche", 118 + "avenue", 119 + "aviator", 120 + "avocado", 121 + "awareness", 122 + "awhile", 123 + "awkward", 124 + "awning", 125 + "awoke", 126 + "axially", 127 + "azalea", 128 + "babbling", 129 + "backpack", 130 + "badass", 131 + "bagpipe", 132 + "bakery", 133 + "balancing", 134 + "bamboo", 135 + "banana", 136 + "barracuda", 137 + "basket", 138 + "bathrobe", 139 + "bazooka", 140 + "blade", 141 + "blender", 142 + "blimp", 143 + "blouse", 144 + "blurred", 145 + "boatyard", 146 + "bobcat", 147 + "body", 148 + "bogusness", 149 + "bohemian", 150 + "boiler", 151 + "bonnet", 152 + "boots", 153 + "borough", 154 + "bossiness", 155 + "bottle", 156 + "bouquet", 157 + "boxlike", 158 + "breath", 159 + "briefcase", 160 + "broom", 161 + "brushes", 162 + "bubblegum", 163 + "buckle", 164 + "buddhist", 165 + "buffalo", 166 + "bullfrog", 167 + "bunny", 168 + "busboy", 169 + "buzzard", 170 + "cabin", 171 + "cactus", 172 + "cadillac", 173 + "cafeteria", 174 + "cage", 175 + "cahoots", 176 + "cajoling", 177 + "cakewalk", 178 + "calculator", 179 + "camera", 180 + "canister", 181 + "capsule", 182 + "carrot", 183 + "cashew", 184 + "cathedral", 185 + "caucasian", 186 + "caviar", 187 + "ceasefire", 188 + "cedar", 189 + "celery", 190 + "cement", 191 + "census", 192 + "ceramics", 193 + "cesspool", 194 + "chalkboard", 195 + "cheesecake", 196 + "chimney", 197 + "chlorine", 198 + "chopsticks", 199 + "chrome", 200 + "chute", 201 + "cilantro", 202 + "cinnamon", 203 + "circle", 204 + "cityscape", 205 + "civilian", 206 + "clay", 207 + "clergyman", 208 + "clipboard", 209 + "clock", 210 + "clubhouse", 211 + "coathanger", 212 + "cobweb", 213 + "coconut", 214 + "codeword", 215 + "coexistent", 216 + "coffeecake", 217 + "cognitive", 218 + "cohabitate", 219 + "collarbone", 220 + "computer", 221 + "confetti", 222 + "copier", 223 + "cornea", 224 + "cosmetics", 225 + "cotton", 226 + "couch", 227 + "coverless", 228 + "coyote", 229 + "coziness", 230 + "crawfish", 231 + "crewmember", 232 + "crib", 233 + "croissant", 234 + "crumble", 235 + "crystal", 236 + "cubical", 237 + "cucumber", 238 + "cuddly", 239 + "cufflink", 240 + "cuisine", 241 + "culprit", 242 + "cup", 243 + "curry", 244 + "cushion", 245 + "cuticle", 246 + "cybernetic", 247 + "cyclist", 248 + "cylinder", 249 + "cymbal", 250 + "cynicism", 251 + "cypress", 252 + "cytoplasm", 253 + "dachshund", 254 + "daffodil", 255 + "dagger", 256 + "dairy", 257 + "dalmatian", 258 + "dandelion", 259 + "dartboard", 260 + "dastardly", 261 + "datebook", 262 + "daughter", 263 + "dawn", 264 + "daytime", 265 + "dazzler", 266 + "dealer", 267 + "debris", 268 + "decal", 269 + "dedicate", 270 + "deepness", 271 + "defrost", 272 + "degree", 273 + "dehydrator", 274 + "deliverer", 275 + "democrat", 276 + "dentist", 277 + "deodorant", 278 + "depot", 279 + "deranged", 280 + "desktop", 281 + "detergent", 282 + "device", 283 + "dexterity", 284 + "diamond", 285 + "dibs", 286 + "dictionary", 287 + "diffuser", 288 + "digit", 289 + "dilated", 290 + "dimple", 291 + "dinnerware", 292 + "dioxide", 293 + "diploma", 294 + "directory", 295 + "dishcloth", 296 + "ditto", 297 + "dividers", 298 + "dizziness", 299 + "doctor", 300 + "dodge", 301 + "doll", 302 + "dominoes", 303 + "donut", 304 + "doorstep", 305 + "dorsal", 306 + "double", 307 + "downstairs", 308 + "dozed", 309 + "drainpipe", 310 + "dresser", 311 + "driftwood", 312 + "droppings", 313 + "drum", 314 + "dryer", 315 + "dubiously", 316 + "duckling", 317 + "duffel", 318 + "dugout", 319 + "dumpster", 320 + "duplex", 321 + "durable", 322 + "dustpan", 323 + "dutiful", 324 + "duvet", 325 + "dwarfism", 326 + "dwelling", 327 + "dwindling", 328 + "dynamite", 329 + "dyslexia", 330 + "eagerness", 331 + "earlobe", 332 + "easel", 333 + "eavesdrop", 334 + "ebook", 335 + "eccentric", 336 + "echoless", 337 + "eclipse", 338 + "ecosystem", 339 + "ecstasy", 340 + "edged", 341 + "editor", 342 + "educator", 343 + "eelworm", 344 + "eerie", 345 + "effects", 346 + "eggnog", 347 + "egomaniac", 348 + "ejection", 349 + "elastic", 350 + "elbow", 351 + "elderly", 352 + "elephant", 353 + "elfishly", 354 + "eliminator", 355 + "elk", 356 + "elliptical", 357 + "elongated", 358 + "elsewhere", 359 + "elusive", 360 + "elves", 361 + "emancipate", 362 + "embroidery", 363 + "emcee", 364 + "emerald", 365 + "emission", 366 + "emoticon", 367 + "emperor", 368 + "emulate", 369 + "enactment", 370 + "enchilada", 371 + "endorphin", 372 + "energy", 373 + "enforcer", 374 + "engine", 375 + "enhance", 376 + "enigmatic", 377 + "enjoyably", 378 + "enlarged", 379 + "enormous", 380 + "enquirer", 381 + "enrollment", 382 + "ensemble", 383 + "entryway", 384 + "enunciate", 385 + "envoy", 386 + "enzyme", 387 + "epidemic", 388 + "equipment", 389 + "erasable", 390 + "ergonomic", 391 + "erratic", 392 + "eruption", 393 + "escalator", 394 + "eskimo", 395 + "esophagus", 396 + "espresso", 397 + "essay", 398 + "estrogen", 399 + "etching", 400 + "eternal", 401 + "ethics", 402 + "etiquette", 403 + "eucalyptus", 404 + "eulogy", 405 + "euphemism", 406 + "euthanize", 407 + "evacuation", 408 + "evergreen", 409 + "evidence", 410 + "evolution", 411 + "exam", 412 + "excerpt", 413 + "exerciser", 414 + "exfoliate", 415 + "exhale", 416 + "exist", 417 + "exorcist", 418 + "explode", 419 + "exquisite", 420 + "exterior", 421 + "exuberant", 422 + "fabric", 423 + "factory", 424 + "faded", 425 + "failsafe", 426 + "falcon", 427 + "family", 428 + "fanfare", 429 + "fasten", 430 + "faucet", 431 + "favorite", 432 + "feasibly", 433 + "february", 434 + "federal", 435 + "feedback", 436 + "feigned", 437 + "feline", 438 + "femur", 439 + "fence", 440 + "ferret", 441 + "festival", 442 + "fettuccine", 443 + "feudalist", 444 + "feverish", 445 + "fiberglass", 446 + "fictitious", 447 + "fiddle", 448 + "figurine", 449 + "fillet", 450 + "finalist", 451 + "fiscally", 452 + "fixture", 453 + "flashlight", 454 + "fleshiness", 455 + "flight", 456 + "florist", 457 + "flypaper", 458 + "foamless", 459 + "focus", 460 + "foggy", 461 + "folksong", 462 + "fondue", 463 + "footpath", 464 + "fossil", 465 + "fountain", 466 + "fox", 467 + "fragment", 468 + "freeway", 469 + "fridge", 470 + "frosting", 471 + "fruit", 472 + "fryingpan", 473 + "gadget", 474 + "gainfully", 475 + "gallstone", 476 + "gamekeeper", 477 + "gangway", 478 + "garlic", 479 + "gaslight", 480 + "gathering", 481 + "gauntlet", 482 + "gearbox", 483 + "gecko", 484 + "gem", 485 + "generator", 486 + "geographer", 487 + "gerbil", 488 + "gesture", 489 + "getaway", 490 + "geyser", 491 + "ghoulishly", 492 + "gibberish", 493 + "giddiness", 494 + "giftshop", 495 + "gigabyte", 496 + "gimmick", 497 + "giraffe", 498 + "giveaway", 499 + "gizmo", 500 + "glasses", 501 + "gleeful", 502 + "glisten", 503 + "glove", 504 + "glucose", 505 + "glycerin", 506 + "gnarly", 507 + "gnomish", 508 + "goatskin", 509 + "goggles", 510 + "goldfish", 511 + "gong", 512 + "gooey", 513 + "gorgeous", 514 + "gosling", 515 + "gothic", 516 + "gourmet", 517 + "governor", 518 + "grape", 519 + "greyhound", 520 + "grill", 521 + "groundhog", 522 + "grumbling", 523 + "guacamole", 524 + "guerrilla", 525 + "guitar", 526 + "gullible", 527 + "gumdrop", 528 + "gurgling", 529 + "gusto", 530 + "gutless", 531 + "gymnast", 532 + "gynecology", 533 + "gyration", 534 + "habitat", 535 + "hacking", 536 + "haggard", 537 + "haiku", 538 + "halogen", 539 + "hamburger", 540 + "handgun", 541 + "happiness", 542 + "hardhat", 543 + "hastily", 544 + "hatchling", 545 + "haughty", 546 + "hazelnut", 547 + "headband", 548 + "hedgehog", 549 + "hefty", 550 + "heinously", 551 + "helmet", 552 + "hemoglobin", 553 + "henceforth", 554 + "herbs", 555 + "hesitation", 556 + "hexagon", 557 + "hubcap", 558 + "huddling", 559 + "huff", 560 + "hugeness", 561 + "hullabaloo", 562 + "human", 563 + "hunter", 564 + "hurricane", 565 + "hushing", 566 + "hyacinth", 567 + "hybrid", 568 + "hydrant", 569 + "hygienist", 570 + "hypnotist", 571 + "ibuprofen", 572 + "icepack", 573 + "icing", 574 + "iconic", 575 + "identical", 576 + "idiocy", 577 + "idly", 578 + "igloo", 579 + "ignition", 580 + "iguana", 581 + "illuminate", 582 + "imaging", 583 + "imbecile", 584 + "imitator", 585 + "immigrant", 586 + "imprint", 587 + "iodine", 588 + "ionosphere", 589 + "ipad", 590 + "iphone", 591 + "iridescent", 592 + "irksome", 593 + "iron", 594 + "irrigation", 595 + "island", 596 + "isotope", 597 + "issueless", 598 + "italicize", 599 + "itemizer", 600 + "itinerary", 601 + "itunes", 602 + "ivory", 603 + "jabbering", 604 + "jackrabbit", 605 + "jaguar", 606 + "jailhouse", 607 + "jalapeno", 608 + "jamboree", 609 + "janitor", 610 + "jarring", 611 + "jasmine", 612 + "jaundice", 613 + "jawbreaker", 614 + "jaywalker", 615 + "jazz", 616 + "jealous", 617 + "jeep", 618 + "jelly", 619 + "jeopardize", 620 + "jersey", 621 + "jetski", 622 + "jezebel", 623 + "jiffy", 624 + "jigsaw", 625 + "jingling", 626 + "jobholder", 627 + "jockstrap", 628 + "jogging", 629 + "john", 630 + "joinable", 631 + "jokingly", 632 + "journal", 633 + "jovial", 634 + "joystick", 635 + "jubilant", 636 + "judiciary", 637 + "juggle", 638 + "juice", 639 + "jujitsu", 640 + "jukebox", 641 + "jumpiness", 642 + "junkyard", 643 + "juror", 644 + "justifying", 645 + "juvenile", 646 + "kabob", 647 + "kamikaze", 648 + "kangaroo", 649 + "karate", 650 + "kayak", 651 + "keepsake", 652 + "kennel", 653 + "kerosene", 654 + "ketchup", 655 + "khaki", 656 + "kickstand", 657 + "kilogram", 658 + "kimono", 659 + "kingdom", 660 + "kiosk", 661 + "kissing", 662 + "kite", 663 + "kleenex", 664 + "knapsack", 665 + "kneecap", 666 + "knickers", 667 + "koala", 668 + "krypton", 669 + "laboratory", 670 + "ladder", 671 + "lakefront", 672 + "lantern", 673 + "laptop", 674 + "laryngitis", 675 + "lasagna", 676 + "latch", 677 + "laundry", 678 + "lavender", 679 + "laxative", 680 + "lazybones", 681 + "lecturer", 682 + "leftover", 683 + "leggings", 684 + "leisure", 685 + "lemon", 686 + "length", 687 + "leopard", 688 + "leprechaun", 689 + "lettuce", 690 + "leukemia", 691 + "levers", 692 + "lewdness", 693 + "liability", 694 + "library", 695 + "licorice", 696 + "lifeboat", 697 + "lightbulb", 698 + "likewise", 699 + "lilac", 700 + "limousine", 701 + "lint", 702 + "lioness", 703 + "lipstick", 704 + "liquid", 705 + "listless", 706 + "litter", 707 + "liverwurst", 708 + "lizard", 709 + "llama", 710 + "luau", 711 + "lubricant", 712 + "lucidity", 713 + "ludicrous", 714 + "luggage", 715 + "lukewarm", 716 + "lullaby", 717 + "lumberjack", 718 + "lunchbox", 719 + "luridness", 720 + "luscious", 721 + "luxurious", 722 + "lyrics", 723 + "macaroni", 724 + "maestro", 725 + "magazine", 726 + "mahogany", 727 + "maimed", 728 + "majority", 729 + "makeover", 730 + "malformed", 731 + "mammal", 732 + "mango", 733 + "mapmaker", 734 + "marbles", 735 + "massager", 736 + "matchstick", 737 + "maverick", 738 + "maximum", 739 + "mayonnaise", 740 + "moaning", 741 + "mobilize", 742 + "moccasin", 743 + "modify", 744 + "moisture", 745 + "molecule", 746 + "momentum", 747 + "monastery", 748 + "moonshine", 749 + "mortuary", 750 + "mosquito", 751 + "motorcycle", 752 + "mousetrap", 753 + "movie", 754 + "mower", 755 + "mozzarella", 756 + "muckiness", 757 + "mudflow", 758 + "mugshot", 759 + "mule", 760 + "mummy", 761 + "mundane", 762 + "muppet", 763 + "mural", 764 + "mustard", 765 + "mutation", 766 + "myriad", 767 + "myspace", 768 + "myth", 769 + "nail", 770 + "namesake", 771 + "nanosecond", 772 + "napkin", 773 + "narrator", 774 + "nastiness", 775 + "natives", 776 + "nautically", 777 + "navigate", 778 + "nearest", 779 + "nebula", 780 + "nectar", 781 + "nefarious", 782 + "negotiator", 783 + "neither", 784 + "nemesis", 785 + "neoliberal", 786 + "nephew", 787 + "nervously", 788 + "nest", 789 + "netting", 790 + "neuron", 791 + "nevermore", 792 + "nextdoor", 793 + "nicotine", 794 + "niece", 795 + "nimbleness", 796 + "nintendo", 797 + "nirvana", 798 + "nuclear", 799 + "nugget", 800 + "nuisance", 801 + "nullify", 802 + "numbing", 803 + "nuptials", 804 + "nursery", 805 + "nutcracker", 806 + "nylon", 807 + "oasis", 808 + "oat", 809 + "obediently", 810 + "obituary", 811 + "object", 812 + "obliterate", 813 + "obnoxious", 814 + "observer", 815 + "obtain", 816 + "obvious", 817 + "occupation", 818 + "oceanic", 819 + "octopus", 820 + "ocular", 821 + "office", 822 + "oftentimes", 823 + "oiliness", 824 + "ointment", 825 + "older", 826 + "olympics", 827 + "omissible", 828 + "omnivorous", 829 + "oncoming", 830 + "onion", 831 + "onlooker", 832 + "onstage", 833 + "onward", 834 + "onyx", 835 + "oomph", 836 + "opaquely", 837 + "opera", 838 + "opium", 839 + "opossum", 840 + "opponent", 841 + "optical", 842 + "opulently", 843 + "oscillator", 844 + "osmosis", 845 + "ostrich", 846 + "otherwise", 847 + "ought", 848 + "outhouse", 849 + "ovation", 850 + "oven", 851 + "owlish", 852 + "oxford", 853 + "oxidize", 854 + "oxygen", 855 + "oyster", 856 + "ozone", 857 + "pacemaker", 858 + "padlock", 859 + "pageant", 860 + "pajamas", 861 + "palm", 862 + "pamphlet", 863 + "pantyhose", 864 + "paprika", 865 + "parakeet", 866 + "passport", 867 + "patio", 868 + "pauper", 869 + "pavement", 870 + "payphone", 871 + "pebble", 872 + "peculiarly", 873 + "pedometer", 874 + "pegboard", 875 + "pelican", 876 + "penguin", 877 + "peony", 878 + "pepperoni", 879 + "peroxide", 880 + "pesticide", 881 + "petroleum", 882 + "pewter", 883 + "pharmacy", 884 + "pheasant", 885 + "phonebook", 886 + "phrasing", 887 + "physician", 888 + "plank", 889 + "pledge", 890 + "plotted", 891 + "plug", 892 + "plywood", 893 + "pneumonia", 894 + "podiatrist", 895 + "poetic", 896 + "pogo", 897 + "poison", 898 + "poking", 899 + "policeman", 900 + "poncho", 901 + "popcorn", 902 + "porcupine", 903 + "postcard", 904 + "poultry", 905 + "powerboat", 906 + "prairie", 907 + "pretzel", 908 + "princess", 909 + "propeller", 910 + "prune", 911 + "pry", 912 + "pseudo", 913 + "psychopath", 914 + "publisher", 915 + "pucker", 916 + "pueblo", 917 + "pulley", 918 + "pumpkin", 919 + "punchbowl", 920 + "puppy", 921 + "purse", 922 + "pushup", 923 + "putt", 924 + "puzzle", 925 + "pyramid", 926 + "python", 927 + "quarters", 928 + "quesadilla", 929 + "quilt", 930 + "quote", 931 + "racoon", 932 + "radish", 933 + "ragweed", 934 + "railroad", 935 + "rampantly", 936 + "rancidity", 937 + "rarity", 938 + "raspberry", 939 + "ravishing", 940 + "rearrange", 941 + "rebuilt", 942 + "receipt", 943 + "reentry", 944 + "refinery", 945 + "register", 946 + "rehydrate", 947 + "reimburse", 948 + "rejoicing", 949 + "rekindle", 950 + "relic", 951 + "remote", 952 + "renovator", 953 + "reopen", 954 + "reporter", 955 + "request", 956 + "rerun", 957 + "reservoir", 958 + "retriever", 959 + "reunion", 960 + "revolver", 961 + "rewrite", 962 + "rhapsody", 963 + "rhetoric", 964 + "rhino", 965 + "rhubarb", 966 + "rhyme", 967 + "ribbon", 968 + "riches", 969 + "ridden", 970 + "rigidness", 971 + "rimmed", 972 + "riptide", 973 + "riskily", 974 + "ritzy", 975 + "riverboat", 976 + "roamer", 977 + "robe", 978 + "rocket", 979 + "romancer", 980 + "ropelike", 981 + "rotisserie", 982 + "roundtable", 983 + "royal", 984 + "rubber", 985 + "rudderless", 986 + "rugby", 987 + "ruined", 988 + "rulebook", 989 + "rummage", 990 + "running", 991 + "rupture", 992 + "rustproof", 993 + "sabotage", 994 + "sacrifice", 995 + "saddlebag", 996 + "saffron", 997 + "sainthood", 998 + "saltshaker", 999 + "samurai", 1000 + "sandworm", 1001 + "sapphire", 1002 + "sardine", 1003 + "sassy", 1004 + "satchel", 1005 + "sauna", 1006 + "savage", 1007 + "saxophone", 1008 + "scarf", 1009 + "scenario", 1010 + "schoolbook", 1011 + "scientist", 1012 + "scooter", 1013 + "scrapbook", 1014 + "sculpture", 1015 + "scythe", 1016 + "secretary", 1017 + "sedative", 1018 + "segregator", 1019 + "seismology", 1020 + "selected", 1021 + "semicolon", 1022 + "senator", 1023 + "septum", 1024 + "sequence", 1025 + "serpent", 1026 + "sesame", 1027 + "settler", 1028 + "severely", 1029 + "shack", 1030 + "shelf", 1031 + "shirt", 1032 + "shovel", 1033 + "shrimp", 1034 + "shuttle", 1035 + "shyness", 1036 + "siamese", 1037 + "sibling", 1038 + "siesta", 1039 + "silicon", 1040 + "simmering", 1041 + "singles", 1042 + "sisterhood", 1043 + "sitcom", 1044 + "sixfold", 1045 + "sizable", 1046 + "skateboard", 1047 + "skeleton", 1048 + "skies", 1049 + "skulk", 1050 + "skylight", 1051 + "slapping", 1052 + "sled", 1053 + "slingshot", 1054 + "sloth", 1055 + "slumbering", 1056 + "smartphone", 1057 + "smelliness", 1058 + "smitten", 1059 + "smokestack", 1060 + "smudge", 1061 + "snapshot", 1062 + "sneezing", 1063 + "sniff", 1064 + "snowsuit", 1065 + "snugness", 1066 + "speakers", 1067 + "sphinx", 1068 + "spider", 1069 + "splashing", 1070 + "sponge", 1071 + "sprout", 1072 + "spur", 1073 + "spyglass", 1074 + "squirrel", 1075 + "statue", 1076 + "steamboat", 1077 + "stingray", 1078 + "stopwatch", 1079 + "strawberry", 1080 + "student", 1081 + "stylus", 1082 + "suave", 1083 + "subway", 1084 + "suction", 1085 + "suds", 1086 + "suffocate", 1087 + "sugar", 1088 + "suitcase", 1089 + "sulphur", 1090 + "superstore", 1091 + "surfer", 1092 + "sushi", 1093 + "swan", 1094 + "sweatshirt", 1095 + "swimwear", 1096 + "sword", 1097 + "sycamore", 1098 + "syllable", 1099 + "symphony", 1100 + "synagogue", 1101 + "syringes", 1102 + "systemize", 1103 + "tablespoon", 1104 + "taco", 1105 + "tadpole", 1106 + "taekwondo", 1107 + "tagalong", 1108 + "takeout", 1109 + "tallness", 1110 + "tamale", 1111 + "tanned", 1112 + "tapestry", 1113 + "tarantula", 1114 + "tastebud", 1115 + "tattoo", 1116 + "tavern", 1117 + "thaw", 1118 + "theater", 1119 + "thimble", 1120 + "thorn", 1121 + "throat", 1122 + "thumb", 1123 + "thwarting", 1124 + "tiara", 1125 + "tidbit", 1126 + "tiebreaker", 1127 + "tiger", 1128 + "timid", 1129 + "tinsel", 1130 + "tiptoeing", 1131 + "tirade", 1132 + "tissue", 1133 + "tractor", 1134 + "tree", 1135 + "tripod", 1136 + "trousers", 1137 + "trucks", 1138 + "tryout", 1139 + "tubeless", 1140 + "tuesday", 1141 + "tugboat", 1142 + "tulip", 1143 + "tumbleweed", 1144 + "tupperware", 1145 + "turtle", 1146 + "tusk", 1147 + "tutorial", 1148 + "tuxedo", 1149 + "tweezers", 1150 + "twins", 1151 + "tyrannical", 1152 + "ultrasound", 1153 + "umbrella", 1154 + "umpire", 1155 + "unarmored", 1156 + "unbuttoned", 1157 + "uncle", 1158 + "underwear", 1159 + "unevenness", 1160 + "unflavored", 1161 + "ungloved", 1162 + "unhinge", 1163 + "unicycle", 1164 + "unjustly", 1165 + "unknown", 1166 + "unlocking", 1167 + "unmarked", 1168 + "unnoticed", 1169 + "unopened", 1170 + "unpaved", 1171 + "unquenched", 1172 + "unroll", 1173 + "unscrewing", 1174 + "untied", 1175 + "unusual", 1176 + "unveiled", 1177 + "unwrinkled", 1178 + "unyielding", 1179 + "unzip", 1180 + "upbeat", 1181 + "upcountry", 1182 + "update", 1183 + "upfront", 1184 + "upgrade", 1185 + "upholstery", 1186 + "upkeep", 1187 + "upload", 1188 + "uppercut", 1189 + "upright", 1190 + "upstairs", 1191 + "uptown", 1192 + "upwind", 1193 + "uranium", 1194 + "urban", 1195 + "urchin", 1196 + "urethane", 1197 + "urgent", 1198 + "urologist", 1199 + "username", 1200 + "usher", 1201 + "utensil", 1202 + "utility", 1203 + "utmost", 1204 + "utopia", 1205 + "utterance", 1206 + "vacuum", 1207 + "vagrancy", 1208 + "valuables", 1209 + "vanquished", 1210 + "vaporizer", 1211 + "varied", 1212 + "vaseline", 1213 + "vegetable", 1214 + "vehicle", 1215 + "velcro", 1216 + "vendor", 1217 + "vertebrae", 1218 + "vestibule", 1219 + "veteran", 1220 + "vexingly", 1221 + "vicinity", 1222 + "videogame", 1223 + "viewfinder", 1224 + "vigilante", 1225 + "village", 1226 + "vinegar", 1227 + "violin", 1228 + "viperfish", 1229 + "virus", 1230 + "visor", 1231 + "vitamins", 1232 + "vivacious", 1233 + "vixen", 1234 + "vocalist", 1235 + "vogue", 1236 + "voicemail", 1237 + "volleyball", 1238 + "voucher", 1239 + "voyage", 1240 + "vulnerable", 1241 + "waffle", 1242 + "wagon", 1243 + "wakeup", 1244 + "walrus", 1245 + "wanderer", 1246 + "wasp", 1247 + "water", 1248 + "waving", 1249 + "wheat", 1250 + "whisper", 1251 + "wholesaler", 1252 + "wick", 1253 + "widow", 1254 + "wielder", 1255 + "wifeless", 1256 + "wikipedia", 1257 + "wildcat", 1258 + "windmill", 1259 + "wipeout", 1260 + "wired", 1261 + "wishbone", 1262 + "wizardry", 1263 + "wobbliness", 1264 + "wolverine", 1265 + "womb", 1266 + "woolworker", 1267 + "workbasket", 1268 + "wound", 1269 + "wrangle", 1270 + "wreckage", 1271 + "wristwatch", 1272 + "wrongdoing", 1273 + "xerox", 1274 + "xylophone", 1275 + "yacht", 1276 + "yahoo", 1277 + "yard", 1278 + "yearbook", 1279 + "yesterday", 1280 + "yiddish", 1281 + "yield", 1282 + "yo", 1283 + "yodel", 1284 + "yogurt", 1285 + "yuppie", 1286 + "zealot", 1287 + "zebra", 1288 + "zeppelin", 1289 + "zestfully", 1290 + "zigzagged", 1291 + "zillion", 1292 + "zipping", 1293 + "zirconium", 1294 + "zodiac", 1295 + "zombie", 1296 + "zookeeper", 1297 + "zucchini", 1298 + ]; 1299 + 1300 + export function getRandomWord(): string { 1301 + return words[Math.floor(Math.random() * words.length)] as string; 1302 + } 1303 + 1304 + export function generatePassphrase(length: number): string { 1305 + const passphrase = []; 1306 + for (let i = 0; i < length; i++) { 1307 + passphrase.push(getRandomWord()); 1308 + } 1309 + return passphrase.join("-"); 1310 + }