@autumnsgrove/groveengine 0.8.5 → 0.9.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 (109) hide show
  1. package/dist/components/WispPanel.svelte +0 -1
  2. package/dist/components/admin/GutterManager.svelte +213 -101
  3. package/dist/components/admin/MarkdownEditor.svelte +6 -3
  4. package/dist/components/custom/ContentWithGutter.svelte +7 -13
  5. package/dist/components/custom/GutterItem.svelte +8 -2
  6. package/dist/components/quota/UpgradePrompt.svelte +1 -0
  7. package/dist/config/domain-blocklist.d.ts +59 -0
  8. package/dist/config/domain-blocklist.js +731 -0
  9. package/dist/config/index.d.ts +3 -1
  10. package/dist/config/index.js +2 -1
  11. package/dist/config/offensive-blocklist.d.ts +44 -0
  12. package/dist/config/offensive-blocklist.js +751 -0
  13. package/dist/config/terrarium.d.ts +109 -0
  14. package/dist/config/terrarium.js +125 -0
  15. package/dist/styles/tokens.css +90 -0
  16. package/dist/types/dom-to-image-more.d.ts +39 -0
  17. package/dist/ui/components/chrome/Footer.svelte +137 -0
  18. package/dist/ui/components/chrome/Footer.svelte.d.ts +11 -0
  19. package/dist/ui/components/chrome/FooterMinimal.svelte +75 -0
  20. package/dist/ui/components/chrome/FooterMinimal.svelte.d.ts +10 -0
  21. package/dist/ui/components/chrome/Header.svelte +113 -0
  22. package/dist/ui/components/chrome/Header.svelte.d.ts +11 -0
  23. package/dist/ui/components/chrome/HeaderMinimal.svelte +68 -0
  24. package/dist/ui/components/chrome/HeaderMinimal.svelte.d.ts +9 -0
  25. package/dist/ui/components/chrome/MobileMenu.svelte +145 -0
  26. package/dist/ui/components/chrome/MobileMenu.svelte.d.ts +9 -0
  27. package/dist/ui/components/chrome/ThemeToggle.svelte +34 -0
  28. package/dist/ui/components/chrome/ThemeToggle.svelte.d.ts +3 -0
  29. package/dist/ui/components/chrome/defaults.d.ts +6 -0
  30. package/dist/ui/components/chrome/defaults.js +65 -0
  31. package/dist/ui/components/chrome/index.d.ts +13 -0
  32. package/dist/ui/components/chrome/index.js +14 -0
  33. package/dist/ui/components/chrome/types.d.ts +19 -0
  34. package/dist/ui/components/chrome/types.js +8 -0
  35. package/dist/ui/components/content/RoadmapPreview.svelte +2 -1
  36. package/dist/ui/components/forms/ContentSearch.svelte +406 -0
  37. package/dist/ui/components/forms/ContentSearch.svelte.d.ts +71 -0
  38. package/dist/ui/components/forms/SearchInput.svelte +0 -1
  39. package/dist/ui/components/forms/filterUtils.d.ts +138 -0
  40. package/dist/ui/components/forms/filterUtils.js +240 -0
  41. package/dist/ui/components/forms/index.d.ts +2 -0
  42. package/dist/ui/components/forms/index.js +5 -1
  43. package/dist/ui/components/gallery/ImageGallery.svelte +17 -3
  44. package/dist/ui/components/gallery/Lightbox.svelte +11 -3
  45. package/dist/ui/components/gallery/ZoomableImage.svelte +13 -2
  46. package/dist/ui/components/icons/index.d.ts +2 -1
  47. package/dist/ui/components/icons/index.js +14 -3
  48. package/dist/ui/components/icons/lucide.d.ts +213 -0
  49. package/dist/ui/components/icons/lucide.js +224 -0
  50. package/dist/ui/components/terrarium/AssetPalette.svelte +207 -0
  51. package/dist/ui/components/terrarium/AssetPalette.svelte.d.ts +7 -0
  52. package/dist/ui/components/terrarium/Canvas.svelte +231 -0
  53. package/dist/ui/components/terrarium/Canvas.svelte.d.ts +14 -0
  54. package/dist/ui/components/terrarium/ExportDialog.svelte +307 -0
  55. package/dist/ui/components/terrarium/ExportDialog.svelte.d.ts +18 -0
  56. package/dist/ui/components/terrarium/PaletteItem.svelte +169 -0
  57. package/dist/ui/components/terrarium/PaletteItem.svelte.d.ts +9 -0
  58. package/dist/ui/components/terrarium/PlacedAsset.svelte +222 -0
  59. package/dist/ui/components/terrarium/PlacedAsset.svelte.d.ts +11 -0
  60. package/dist/ui/components/terrarium/Terrarium.svelte +266 -0
  61. package/dist/ui/components/terrarium/Terrarium.svelte.d.ts +3 -0
  62. package/dist/ui/components/terrarium/Toolbar.svelte +299 -0
  63. package/dist/ui/components/terrarium/Toolbar.svelte.d.ts +24 -0
  64. package/dist/ui/components/terrarium/index.d.ts +31 -0
  65. package/dist/ui/components/terrarium/index.js +33 -0
  66. package/dist/ui/components/terrarium/terrariumState.svelte.d.ts +45 -0
  67. package/dist/ui/components/terrarium/terrariumState.svelte.js +291 -0
  68. package/dist/ui/components/terrarium/types.d.ts +139 -0
  69. package/dist/ui/components/terrarium/types.js +43 -0
  70. package/dist/ui/components/terrarium/utils/export.d.ts +48 -0
  71. package/dist/ui/components/terrarium/utils/export.js +148 -0
  72. package/dist/ui/components/typography/index.d.ts +0 -10
  73. package/dist/ui/components/typography/index.js +1 -12
  74. package/dist/ui/components/ui/CollapsibleSection.svelte +12 -0
  75. package/dist/ui/components/ui/GlassConfirmDialog.svelte +9 -0
  76. package/dist/ui/components/ui/GlassOverlay.svelte +2 -1
  77. package/dist/ui/components/ui/Input.svelte +9 -1
  78. package/dist/ui/components/ui/Input.svelte.d.ts +2 -0
  79. package/dist/ui/components/ui/Textarea.svelte +9 -1
  80. package/dist/ui/components/ui/Textarea.svelte.d.ts +2 -0
  81. package/dist/ui/stores/index.d.ts +6 -0
  82. package/dist/ui/stores/index.js +6 -0
  83. package/dist/ui/stores/season.d.ts +14 -0
  84. package/dist/ui/stores/season.js +65 -0
  85. package/dist/ui/tokens/fonts.d.ts +1 -1
  86. package/dist/ui/tokens/fonts.js +0 -126
  87. package/package.json +46 -22
  88. package/static/fonts/alagard.ttf +0 -0
  89. package/LICENSE +0 -378
  90. package/dist/ui/components/typography/BodoniModa.svelte +0 -17
  91. package/dist/ui/components/typography/BodoniModa.svelte.d.ts +0 -10
  92. package/dist/ui/components/typography/Cormorant.svelte +0 -17
  93. package/dist/ui/components/typography/Cormorant.svelte.d.ts +0 -10
  94. package/dist/ui/components/typography/EBGaramond.svelte +0 -17
  95. package/dist/ui/components/typography/EBGaramond.svelte.d.ts +0 -10
  96. package/dist/ui/components/typography/Fraunces.svelte +0 -17
  97. package/dist/ui/components/typography/Fraunces.svelte.d.ts +0 -10
  98. package/dist/ui/components/typography/InstrumentSans.svelte +0 -17
  99. package/dist/ui/components/typography/InstrumentSans.svelte.d.ts +0 -10
  100. package/dist/ui/components/typography/Lora.svelte +0 -17
  101. package/dist/ui/components/typography/Lora.svelte.d.ts +0 -10
  102. package/dist/ui/components/typography/Luciole.svelte +0 -17
  103. package/dist/ui/components/typography/Luciole.svelte.d.ts +0 -10
  104. package/dist/ui/components/typography/Manrope.svelte +0 -17
  105. package/dist/ui/components/typography/Manrope.svelte.d.ts +0 -10
  106. package/dist/ui/components/typography/Merriweather.svelte +0 -17
  107. package/dist/ui/components/typography/Merriweather.svelte.d.ts +0 -10
  108. package/dist/ui/components/typography/Nunito.svelte +0 -17
  109. package/dist/ui/components/typography/Nunito.svelte.d.ts +0 -10
@@ -0,0 +1,751 @@
1
+ /**
2
+ * Loam - Offensive Content Blocklist
3
+ *
4
+ * Part of the Loam name protection system.
5
+ * This file contains terms blocked for violating the Acceptable Use Policy.
6
+ *
7
+ * Sources:
8
+ * - LDNOOBW (List of Dirty, Naughty, Obscene, and Otherwise Bad Words)
9
+ * - dsojevic/profanity-list (categorized with severity ratings)
10
+ * - GLAAD Anti-LGBTQ Hate Speech Guide
11
+ * - Autistic Hoya's Ableist Language List
12
+ * - ADL Hate Symbols Database
13
+ * - SPLC Extremist Files
14
+ *
15
+ * @see docs/specs/loam-spec.md
16
+ * @module offensive-blocklist
17
+ * @private
18
+ */
19
+ // =============================================================================
20
+ // SLURS - Organized by category
21
+ // Note: These are kept intentionally non-enumerated in documentation
22
+ // =============================================================================
23
+ /**
24
+ * Racial and ethnic slurs
25
+ * Sourced from LDNOOBW and dsojevic/profanity-list (tag: racial)
26
+ */
27
+ const SLURS_RACIAL = [
28
+ // Anti-Black slurs
29
+ 'nigger',
30
+ 'nigga',
31
+ 'nigg3r',
32
+ 'n1gger',
33
+ 'n1gga',
34
+ 'negro',
35
+ 'negr0',
36
+ 'coon',
37
+ 'c00n',
38
+ 'darkie',
39
+ 'sambo',
40
+ 'spook',
41
+ 'jigaboo',
42
+ 'pickaninny',
43
+ 'spade',
44
+ 'tar-baby',
45
+ 'tarbaby',
46
+ 'jungle-bunny',
47
+ 'junglebunny',
48
+ 'porch-monkey',
49
+ 'porchmonkey',
50
+ // Anti-Asian slurs
51
+ 'chink',
52
+ 'ch1nk',
53
+ 'gook',
54
+ 'g00k',
55
+ 'slope',
56
+ 'slant',
57
+ 'slanteye',
58
+ 'slant-eye',
59
+ 'zipperhead',
60
+ 'jap',
61
+ 'nip',
62
+ 'chinaman',
63
+ 'ching-chong',
64
+ 'chingchong',
65
+ 'ch1ng-ch0ng',
66
+ // Anti-Latino/Hispanic slurs
67
+ 'wetback',
68
+ 'w3tback',
69
+ 'spic',
70
+ 'sp1c',
71
+ 'beaner',
72
+ 'b3aner',
73
+ 'greaser',
74
+ // Anti-Indigenous slurs
75
+ 'redskin',
76
+ 'r3dskin',
77
+ 'injun',
78
+ 'squaw',
79
+ 'prairie-nigger',
80
+ 'prairienig',
81
+ // Anti-Semitic slurs
82
+ 'kike',
83
+ 'k1ke',
84
+ 'heeb',
85
+ 'hymie',
86
+ 'yid',
87
+ 'sheeny',
88
+ 'shylock',
89
+ 'jewboy',
90
+ 'jew-boy',
91
+ // Anti-Arab/Muslim slurs
92
+ 'sand-nigger',
93
+ 'sandnigger',
94
+ 'towelhead',
95
+ 'towel-head',
96
+ 'raghead',
97
+ 'rag-head',
98
+ 'camel-jockey',
99
+ 'cameljockey',
100
+ 'hajji',
101
+ 'haji',
102
+ // Anti-Romani slurs
103
+ 'gypsy',
104
+ 'gyp',
105
+ 'pikey',
106
+ // Anti-South Asian slurs
107
+ 'paki',
108
+ 'p4ki',
109
+ 'dothead',
110
+ 'dot-head',
111
+ // General
112
+ 'mudblood',
113
+ 'halfbreed',
114
+ 'half-breed',
115
+ 'mulatto',
116
+ 'mongrel'
117
+ ];
118
+ /**
119
+ * LGBTQ+ slurs
120
+ * Sourced from GLAAD and dsojevic/profanity-list (tag: lgbtq)
121
+ * Note: Some reclaimed terms are in REQUIRES_REVIEW instead
122
+ */
123
+ const SLURS_LGBTQ = [
124
+ // Homophobic slurs
125
+ 'faggot',
126
+ 'f4ggot',
127
+ 'fagg0t',
128
+ 'fag',
129
+ 'f4g',
130
+ 'fags',
131
+ 'faggy',
132
+ 'fairy',
133
+ 'f41ry',
134
+ 'pansy',
135
+ 'homo',
136
+ 'h0mo',
137
+ 'homos',
138
+ 'sodomite',
139
+ 'cocksucker',
140
+ 'c0cksucker',
141
+ 'poof',
142
+ 'poofter',
143
+ 'batty-boy',
144
+ 'battyboy',
145
+ 'bender',
146
+ 'pillow-biter',
147
+ 'pillowbiter',
148
+ 'arse-bandit',
149
+ 'arsebandit',
150
+ 'shirt-lifter',
151
+ 'shirtlifter',
152
+ 'fudge-packer',
153
+ 'fudgepacker',
154
+ 'butt-pirate',
155
+ 'buttpirate',
156
+ // Transphobic slurs
157
+ 'tranny',
158
+ 'tr4nny',
159
+ 'shemale',
160
+ 'sh3male',
161
+ 'she-male',
162
+ 'ladyboy',
163
+ 'lady-boy',
164
+ 'he-she',
165
+ 'heshe',
166
+ 'it-creature',
167
+ 'trap',
168
+ 'shim',
169
+ 'dickgirl',
170
+ 'dick-girl',
171
+ 'chick-with-dick',
172
+ 'chickwithdick',
173
+ // Lesbian-specific slurs (non-reclaimed)
174
+ 'carpet-muncher',
175
+ 'carpetmuncher',
176
+ 'rug-muncher',
177
+ 'rugmuncher',
178
+ 'lesbo',
179
+ 'l3sbo',
180
+ 'lezzie',
181
+ 'lezbo',
182
+ // Bisexual-specific
183
+ 'fence-sitter',
184
+ 'fencesitter'
185
+ ];
186
+ /**
187
+ * Gendered/sexist slurs
188
+ * Sourced from academic research on gendered hate speech
189
+ */
190
+ const SLURS_GENDER = [
191
+ // Primary slurs
192
+ 'cunt',
193
+ 'c0nt',
194
+ 'c-u-n-t',
195
+ 'bitch',
196
+ 'b1tch',
197
+ 'b-i-t-c-h',
198
+ 'slut',
199
+ 'sl0t',
200
+ 'whore',
201
+ 'wh0re',
202
+ 'hoe',
203
+ 'h0e',
204
+ 'ho',
205
+ 'skank',
206
+ 'sk4nk',
207
+ 'slag',
208
+ 'tramp',
209
+ 'trollop',
210
+ // Body-shaming slurs
211
+ 'butterface',
212
+ 'butter-face',
213
+ // Violence-adjacent
214
+ 'cum-dumpster',
215
+ 'cumdumpster',
216
+ 'cum-slut',
217
+ 'cumslut',
218
+ 'cock-sleeve',
219
+ 'cocksleeve',
220
+ // Degrading terms
221
+ 'twat',
222
+ 'tw4t',
223
+ 'gash',
224
+ 'minge',
225
+ 'floozy',
226
+ 'hussy'
227
+ ];
228
+ /**
229
+ * Ableist slurs
230
+ * Sourced from Autistic Hoya, Dictionary.com, UW Medicine
231
+ */
232
+ const SLURS_ABLEIST = [
233
+ // Cognitive disability slurs
234
+ 'retard',
235
+ 'r3tard',
236
+ 'retarded',
237
+ 'r3tarded',
238
+ 'tard',
239
+ 't4rd',
240
+ 'libtard',
241
+ 'l1btard',
242
+ 'fucktard',
243
+ 'mongoloid',
244
+ 'mong0loid',
245
+ 'mong',
246
+ 'moron',
247
+ 'imbecile',
248
+ 'cretin',
249
+ // Physical disability slurs
250
+ 'cripple',
251
+ 'cr1pple',
252
+ 'crippled',
253
+ 'gimp',
254
+ 'g1mp',
255
+ 'gimpy',
256
+ 'spastic',
257
+ 'sp4stic',
258
+ 'spaz',
259
+ 'sp4z',
260
+ 'spazz',
261
+ 'spazzed',
262
+ 'lame',
263
+ // Mental health slurs
264
+ 'psycho',
265
+ 'psych0',
266
+ 'lunatic',
267
+ 'lunat1c',
268
+ 'nutcase',
269
+ 'nutjob',
270
+ 'schizo',
271
+ 'sch1zo',
272
+ 'basket-case',
273
+ 'basketcase',
274
+ // Sensory disability
275
+ 'deaf-and-dumb',
276
+ 'deafdumb',
277
+ 'dumb',
278
+ 'mute'
279
+ ];
280
+ // =============================================================================
281
+ // VIOLENCE & EXTREMISM
282
+ // Sourced from ADL, SPLC, DHS threat assessments
283
+ // =============================================================================
284
+ const VIOLENCE_TERMS = [
285
+ 'killall',
286
+ 'kill-all',
287
+ 'k1llall',
288
+ 'genocide',
289
+ 'gen0cide',
290
+ 'ethnic-cleansing',
291
+ 'ethniccleansing',
292
+ 'holocaust',
293
+ 'h0locaust',
294
+ 'lynching',
295
+ 'lynch',
296
+ 'lynchings',
297
+ 'death-to',
298
+ 'deathto',
299
+ 'murder',
300
+ 'murderer',
301
+ 'terrorist',
302
+ 'terrorism',
303
+ 'terr0rist',
304
+ 'bomber',
305
+ 'suicide-bomber',
306
+ 'shooting',
307
+ 'shooter',
308
+ 'mass-shooter',
309
+ 'massshooter',
310
+ 'massacre',
311
+ 'massacres',
312
+ 'slaughter',
313
+ // Mass shooter glorification (per ADL gaming research)
314
+ 'columbine',
315
+ 'columbiners',
316
+ 'elliot-rodger',
317
+ 'elliotrodger',
318
+ 'saint-elliot',
319
+ 'saintelliot',
320
+ 'going-er',
321
+ 'goinger',
322
+ 'supreme-gentleman',
323
+ 'supremegentleman',
324
+ 'day-of-retribution',
325
+ 'dayofretribution',
326
+ 'beta-uprising',
327
+ 'betauprising',
328
+ // Accelerationist terminology
329
+ 'race-war',
330
+ 'racewar',
331
+ 'rahowa',
332
+ 'r4howa',
333
+ 'racial-holy-war',
334
+ 'boogaloo',
335
+ 'big-igloo',
336
+ 'boog',
337
+ 'accelerationism',
338
+ 'accelerationist',
339
+ 'lone-wolf',
340
+ 'lonewolf',
341
+ 'day-of-the-rope',
342
+ 'dayoftherope',
343
+ 'dotr'
344
+ ];
345
+ const HATE_GROUPS = [
346
+ // Nazi/white supremacist
347
+ 'nazi',
348
+ 'nazis',
349
+ 'n4zi',
350
+ 'n4zis',
351
+ 'neonazi',
352
+ 'neo-nazi',
353
+ 'n30nazi',
354
+ 'skinhead',
355
+ 'skinheads',
356
+ 'sk1nhead',
357
+ 'kkk',
358
+ 'ku-klux-klan',
359
+ 'klan',
360
+ 'klansman',
361
+ 'aryan',
362
+ 'aryan-nation',
363
+ 'aryannation',
364
+ 'aryan-brotherhood',
365
+ 'aryans',
366
+ 'whitepride',
367
+ 'white-pride',
368
+ 'wh1tepride',
369
+ 'whitepower',
370
+ 'white-power',
371
+ 'wh1tepower',
372
+ // Numeric codes (ADL Hate Symbols Database)
373
+ '1488',
374
+ '14-88',
375
+ '14words',
376
+ '14-words',
377
+ 'fourteenwords',
378
+ 'hh88',
379
+ 'sieg-heil',
380
+ 'siegheil',
381
+ 's1egheil',
382
+ 'heil-hitler',
383
+ 'heilhitler',
384
+ 'h3ilhitler',
385
+ // Symbols
386
+ 'black-sun',
387
+ 'blacksun',
388
+ 'sonnenrad',
389
+ 'totenkopf',
390
+ 'ss-bolts',
391
+ 'ssbolts',
392
+ 'blood-and-soil',
393
+ 'bloodandsoil',
394
+ 'blut-und-boden',
395
+ // Active groups (SPLC tracking)
396
+ 'proudboys',
397
+ 'proud-boys',
398
+ 'pr0udboys',
399
+ 'oathkeepers',
400
+ 'oath-keepers',
401
+ '0athkeepers',
402
+ 'threepers',
403
+ 'three-percenters',
404
+ '3percenters',
405
+ '3-percent',
406
+ 'atomwaffen',
407
+ 'atomw4ffen',
408
+ 'identity-evropa',
409
+ 'identityevropa',
410
+ 'patriot-front',
411
+ 'patriotfront',
412
+ 'vanguard-america',
413
+ 'vanguardamerica',
414
+ 'goyim-defense-league',
415
+ 'goyimdefense',
416
+ 'stormfront',
417
+ 'st0rmfront',
418
+ 'daily-stormer',
419
+ 'dailystormer',
420
+ 'combat-18',
421
+ 'combat18',
422
+ 'c18',
423
+ 'hammerskins',
424
+ 'hammerskin',
425
+ 'white-genocide',
426
+ 'whitegenocide',
427
+ 'zog'
428
+ ];
429
+ const TERRORIST_GROUPS = [
430
+ 'isis',
431
+ '1sis',
432
+ 'isil',
433
+ 'daesh',
434
+ 'da3sh',
435
+ 'islamic-state',
436
+ 'islamicstate',
437
+ 'al-qaeda',
438
+ 'alqaeda',
439
+ 'al-qa1da',
440
+ 'al-shabab',
441
+ 'alshabab',
442
+ 'boko-haram',
443
+ 'bokoharam',
444
+ 'taliban',
445
+ 'tal1ban'
446
+ ];
447
+ // =============================================================================
448
+ // SELF-HARM CONTENT
449
+ // Blocked for user safety
450
+ // =============================================================================
451
+ const SELF_HARM = [
452
+ 'suicide',
453
+ 'suicidal',
454
+ 'su1cide',
455
+ 'killmyself',
456
+ 'kill-myself',
457
+ 'k1llmyself',
458
+ 'kms',
459
+ 'selfharm',
460
+ 'self-harm',
461
+ 's3lfharm',
462
+ 'cutting',
463
+ 'cutter',
464
+ 'cutt1ng',
465
+ // Pro-eating disorder
466
+ 'proana',
467
+ 'pro-ana',
468
+ 'pr0ana',
469
+ 'promia',
470
+ 'pro-mia',
471
+ 'pr0mia',
472
+ 'thinspo',
473
+ 'thinspiration',
474
+ 'th1nspo',
475
+ 'bonespo',
476
+ 'bonespiration',
477
+ 'b0nespo',
478
+ 'meanspo',
479
+ 'm3anspo',
480
+ 'ana-tips',
481
+ 'anatips',
482
+ 'mia-tips',
483
+ 'miatips',
484
+ 'edtwt',
485
+ 'ed-twt',
486
+ 'shtwt',
487
+ 'sh-twt',
488
+ 'ana-buddy',
489
+ 'anabuddy',
490
+ // Other self-harm
491
+ 'an-hero',
492
+ 'anhero',
493
+ 'ldar',
494
+ 'lie-down-and-rot',
495
+ 'rope-day',
496
+ 'ropeday',
497
+ 'neck-rope',
498
+ 'neckrope',
499
+ 'end-it-all',
500
+ 'enditall',
501
+ 'want-to-die',
502
+ 'wanttod1e'
503
+ ];
504
+ // =============================================================================
505
+ // EXPLOITATION CONTENT
506
+ // =============================================================================
507
+ const EXPLOITATION = [
508
+ 'pedo',
509
+ 'p3do',
510
+ 'pedophile',
511
+ 'pedoph1le',
512
+ 'paedo',
513
+ 'paedophile',
514
+ 'child-lover',
515
+ 'childlover',
516
+ 'minor-attracted',
517
+ 'minorattracted',
518
+ 'hebephile',
519
+ 'hebeph1le',
520
+ 'jailbait',
521
+ 'ja1lbait',
522
+ 'underage',
523
+ 'und3rage',
524
+ 'preteen',
525
+ 'pre-teen',
526
+ 'pr3teen',
527
+ 'lolita',
528
+ 'l0lita',
529
+ 'loli',
530
+ 'l0li',
531
+ 'shota',
532
+ 'sh0ta',
533
+ 'toddlercon',
534
+ 't0ddlercon',
535
+ 'grooming',
536
+ 'gro0ming',
537
+ 'groomer',
538
+ 'groomers',
539
+ 'child-predator',
540
+ 'childpredator'
541
+ ];
542
+ // =============================================================================
543
+ // EXPLICIT SEXUAL (for username context)
544
+ // =============================================================================
545
+ const EXPLICIT_SEXUAL = [
546
+ 'xxx',
547
+ 'xxxx',
548
+ 'porn',
549
+ 'p0rn',
550
+ 'porno',
551
+ 'pornhub',
552
+ 'xvideos',
553
+ 'xnxx',
554
+ 'hentai',
555
+ 'h3ntai',
556
+ 'camgirl',
557
+ 'camboy',
558
+ 'escort',
559
+ 'escorts',
560
+ 'hooker',
561
+ 'prostitute'
562
+ ];
563
+ // =============================================================================
564
+ // INCEL TERMINOLOGY
565
+ // Per ADL: "most violent community within the manosphere"
566
+ // =============================================================================
567
+ const INCEL_TERMS = [
568
+ 'incel',
569
+ '1ncel',
570
+ 'incels',
571
+ 'blackpill',
572
+ 'black-pill',
573
+ 'blackpilled',
574
+ 'foid',
575
+ 'f0id',
576
+ 'foids',
577
+ 'femoid',
578
+ 'fem0id',
579
+ 'femoids',
580
+ 'roastie',
581
+ 'roasties',
582
+ 'r0astie'
583
+ ];
584
+ // =============================================================================
585
+ // UTILITIES
586
+ // =============================================================================
587
+ /**
588
+ * Leetspeak/obfuscation variants
589
+ * Common character substitutions to evade filters
590
+ */
591
+ function generateLeetVariants(term) {
592
+ const substitutions = {
593
+ a: ['4', '@'],
594
+ e: ['3'],
595
+ i: ['1', '!'],
596
+ o: ['0'],
597
+ s: ['5', '$'],
598
+ t: ['7'],
599
+ l: ['1'],
600
+ g: ['9']
601
+ };
602
+ const variants = [term];
603
+ // Generate single-substitution variants
604
+ for (const [char, replacements] of Object.entries(substitutions)) {
605
+ if (term.includes(char)) {
606
+ for (const replacement of replacements) {
607
+ variants.push(term.replace(new RegExp(char, 'g'), replacement));
608
+ }
609
+ }
610
+ }
611
+ return variants;
612
+ }
613
+ // =============================================================================
614
+ // COMBINED EXPORTS
615
+ // =============================================================================
616
+ /**
617
+ * All offensive terms combined
618
+ * Includes base terms and generated variants
619
+ */
620
+ export const OFFENSIVE_TERMS = [
621
+ ...SLURS_RACIAL,
622
+ ...SLURS_LGBTQ,
623
+ ...SLURS_GENDER,
624
+ ...SLURS_ABLEIST,
625
+ ...VIOLENCE_TERMS,
626
+ ...HATE_GROUPS,
627
+ ...TERRORIST_GROUPS,
628
+ ...SELF_HARM,
629
+ ...EXPLOITATION,
630
+ ...EXPLICIT_SEXUAL,
631
+ ...INCEL_TERMS
632
+ ].flatMap((term) => generateLeetVariants(term));
633
+ /**
634
+ * Fast lookup Set
635
+ */
636
+ export const OFFENSIVE_SET = new Set(OFFENSIVE_TERMS);
637
+ /**
638
+ * Terms requiring substring matching (hate groups, violence)
639
+ */
640
+ const DANGEROUS_SUBSTRINGS = [...HATE_GROUPS, ...VIOLENCE_TERMS, ...TERRORIST_GROUPS];
641
+ /**
642
+ * Severe slurs that should be caught even as substrings.
643
+ * These are carefully selected to minimize false positives.
644
+ * Excludes short terms (3 chars or less) that might appear in legitimate words.
645
+ */
646
+ const SLUR_SUBSTRINGS = [
647
+ // Racial slurs (4+ chars, unlikely to appear in legitimate words)
648
+ 'nigger',
649
+ 'nigga',
650
+ 'chink',
651
+ 'wetback',
652
+ 'beaner',
653
+ 'redskin',
654
+ 'sandnigger',
655
+ 'towelhead',
656
+ 'raghead',
657
+ // LGBTQ slurs (4+ chars)
658
+ 'faggot',
659
+ 'tranny',
660
+ 'shemale',
661
+ // Ableist slurs (4+ chars) - Note: "retard" handled separately with word boundary check
662
+ 'retarded',
663
+ 'spastic',
664
+ // Exploitation (4+ chars) - Note: "pedo" handled separately with word boundary check
665
+ 'pedophile',
666
+ 'jailbait',
667
+ 'lolita',
668
+ 'groomer'
669
+ ];
670
+ /**
671
+ * Terms that need word boundary checking to avoid false positives.
672
+ * Example: "retard" could match "fire-retardant-blog"
673
+ */
674
+ const BOUNDARY_CHECK_TERMS = [
675
+ 'retard', // Could match "retardant"
676
+ 'pedo' // Could match "pedometer" (rare, but possible)
677
+ ];
678
+ /**
679
+ * Check if a term appears as a word (not embedded in another word)
680
+ * Uses simple boundary detection: term is at start/end or surrounded by non-letters
681
+ */
682
+ function hasWordBoundary(text, term) {
683
+ const index = text.indexOf(term);
684
+ if (index === -1)
685
+ return false;
686
+ const beforeChar = index > 0 ? text[index - 1] : '';
687
+ const afterChar = index + term.length < text.length ? text[index + term.length] : '';
688
+ // Check if bounded by non-letter characters or string boundaries
689
+ const beforeOk = !beforeChar || !/[a-z]/.test(beforeChar);
690
+ const afterOk = !afterChar || !/[a-z]/.test(afterChar);
691
+ return beforeOk && afterOk;
692
+ }
693
+ /**
694
+ * Check if a username contains offensive content
695
+ * Uses exact matching and substring matching for dangerous/severe terms
696
+ *
697
+ * @param username - The username to check
698
+ * @returns true if offensive content detected
699
+ */
700
+ export function containsOffensiveContent(username) {
701
+ const normalized = username.toLowerCase().replace(/-/g, '');
702
+ // Exact match
703
+ if (OFFENSIVE_SET.has(normalized)) {
704
+ return true;
705
+ }
706
+ // Also check with hyphens preserved
707
+ if (OFFENSIVE_SET.has(username.toLowerCase())) {
708
+ return true;
709
+ }
710
+ // Substring match for dangerous terms (hate groups, violence, terrorist)
711
+ for (const term of DANGEROUS_SUBSTRINGS) {
712
+ const normalizedTerm = term.replace(/-/g, '');
713
+ if (normalized.includes(normalizedTerm)) {
714
+ return true;
715
+ }
716
+ }
717
+ // Substring match for severe slurs (catches "badword123" patterns)
718
+ for (const slur of SLUR_SUBSTRINGS) {
719
+ if (normalized.includes(slur)) {
720
+ return true;
721
+ }
722
+ }
723
+ // Word boundary check for terms prone to false positives
724
+ for (const term of BOUNDARY_CHECK_TERMS) {
725
+ if (hasWordBoundary(normalized, term)) {
726
+ return true;
727
+ }
728
+ }
729
+ return false;
730
+ }
731
+ /**
732
+ * Terms that may be reclaimed/identity terms
733
+ * These require manual review rather than automatic blocking
734
+ */
735
+ export const REQUIRES_REVIEW = [
736
+ 'queer',
737
+ 'dyke',
738
+ 'femme',
739
+ 'butch',
740
+ 'twink',
741
+ 'bear',
742
+ 'leather',
743
+ 'crip' // disability reclaimed term
744
+ ];
745
+ /**
746
+ * Check if a term requires manual review
747
+ */
748
+ export function requiresReview(username) {
749
+ const normalized = username.toLowerCase();
750
+ return REQUIRES_REVIEW.some((term) => normalized.includes(term));
751
+ }