@esposter/shared 4.0.0 → 4.1.1

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 (3) hide show
  1. package/dist/index.d.ts +326 -126
  2. package/dist/index.js +1378 -74
  3. package/package.json +12 -11
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { z } from "zod";
2
2
  import { ResultAsync, fromThrowable } from "neverthrow";
3
3
  import { parse } from "node-html-parser";
4
- import baseSanitizeHtml from "sanitize-html";
4
+ import mimeDatabase from "mime-db/db.json" with { type: "json" };
5
+ import { defaultTreeAdapter, html as html$1, parseFragment } from "parse5";
5
6
  //#region src/models/error/ForbiddenError.ts
6
7
  var ForbiddenError = class extends Error {
7
8
  constructor(message) {
@@ -42,6 +43,53 @@ var WordFilteredError = class extends Error {
42
43
  }
43
44
  };
44
45
  //#endregion
46
+ //#region src/models/shared/Operation.ts
47
+ let Operation = /* @__PURE__ */ function(Operation) {
48
+ Operation["Create"] = "Create";
49
+ Operation["Delete"] = "Delete";
50
+ Operation["Push"] = "Push";
51
+ Operation["Read"] = "Read";
52
+ Operation["Unshift"] = "Unshift";
53
+ Operation["Update"] = "Update";
54
+ return Operation;
55
+ }({});
56
+ //#endregion
57
+ //#region src/models/eventEmitter/TypedEventEmitter.ts
58
+ var TypedEventEmitter = class {
59
+ #entriesMap = /* @__PURE__ */ new Map();
60
+ emit(event, ...args) {
61
+ const entries = this.#entriesMap.get(event) ?? [];
62
+ if (entries.length === 0) return false;
63
+ this.#setEntries(event, entries.filter((entry) => !entry.isOnce));
64
+ for (const { listener } of entries) listener(...args);
65
+ return true;
66
+ }
67
+ off(event, listener) {
68
+ this.#setEntries(event, (this.#entriesMap.get(event) ?? []).filter((entry) => entry.listener !== listener));
69
+ }
70
+ on(event, listener) {
71
+ this.#addEntry(event, listener, false);
72
+ }
73
+ once(event, listener) {
74
+ this.#addEntry(event, listener, true);
75
+ }
76
+ removeAllListeners(event) {
77
+ if (event === void 0) this.#entriesMap.clear();
78
+ else this.#entriesMap.delete(event);
79
+ }
80
+ #addEntry(event, listener, isOnce) {
81
+ if (typeof listener !== "function") throw new InvalidOperationError("Create", String(event), "The listener must be a function");
82
+ this.#setEntries(event, [...this.#entriesMap.get(event) ?? [], {
83
+ isOnce,
84
+ listener
85
+ }]);
86
+ }
87
+ #setEntries(event, entries) {
88
+ if (entries.length === 0) this.#entriesMap.delete(event);
89
+ else this.#entriesMap.set(event, entries);
90
+ }
91
+ };
92
+ //#endregion
45
93
  //#region src/models/message/MentionType.ts
46
94
  let MentionType = /* @__PURE__ */ function(MentionType) {
47
95
  MentionType["Role"] = "role";
@@ -49,6 +97,13 @@ let MentionType = /* @__PURE__ */ function(MentionType) {
49
97
  return MentionType;
50
98
  }({});
51
99
  //#endregion
100
+ //#region src/models/object/ObjectMethod.ts
101
+ let ObjectMethod = /* @__PURE__ */ function(ObjectMethod) {
102
+ ObjectMethod["ToString"] = "toString";
103
+ ObjectMethod["ValueOf"] = "valueOf";
104
+ return ObjectMethod;
105
+ }({});
106
+ //#endregion
52
107
  //#region src/services/app/constants.ts
53
108
  const MAX_READ_LIMIT = 1e3;
54
109
  const SITE_NAME = "Esposter";
@@ -106,17 +161,6 @@ var ItemMetadata = class {
106
161
  updatedAt = /* @__PURE__ */ new Date();
107
162
  };
108
163
  //#endregion
109
- //#region src/models/shared/Operation.ts
110
- let Operation = /* @__PURE__ */ function(Operation) {
111
- Operation["Create"] = "Create";
112
- Operation["Delete"] = "Delete";
113
- Operation["Push"] = "Push";
114
- Operation["Read"] = "Read";
115
- Operation["Unshift"] = "Unshift";
116
- Operation["Update"] = "Update";
117
- return Operation;
118
- }({});
119
- //#endregion
120
164
  //#region src/util/reactivity/getRawData.ts
121
165
  const getRawData = (data) => {
122
166
  const raw = data && data.__v_raw;
@@ -153,6 +197,15 @@ const getResult = (callback) => fromThrowable(callback, toAppError)();
153
197
  //#region src/services/error/getResultAsync.ts
154
198
  const getResultAsync = (callback) => ResultAsync.fromThrowable(callback, toAppError)();
155
199
  //#endregion
200
+ //#region src/services/error/reportFinalizerError.ts
201
+ const reportFinalizerError = (callbackResult, finalizerError) => {
202
+ callbackResult.match(() => {
203
+ throw finalizerError;
204
+ }, () => {
205
+ console.error(finalizerError);
206
+ });
207
+ };
208
+ //#endregion
156
209
  //#region src/util/function/noop.ts
157
210
  const noop = () => {};
158
211
  //#endregion
@@ -160,11 +213,7 @@ const noop = () => {};
160
213
  const withFinalizer = (callback, finalizer) => {
161
214
  const callbackResult = getResult(callback);
162
215
  if (finalizer) getResult(finalizer).match(noop, (error) => {
163
- callbackResult.match(() => {
164
- throw error;
165
- }, () => {
166
- console.error(error);
167
- });
216
+ reportFinalizerError(callbackResult, error);
168
217
  });
169
218
  return callbackResult.match((value) => value, (error) => {
170
219
  throw error;
@@ -175,17 +224,142 @@ const withFinalizer = (callback, finalizer) => {
175
224
  const withFinalizerAsync = async (callback, finalizer) => {
176
225
  const callbackResult = await getResultAsync(async () => callback());
177
226
  if (finalizer) await getResultAsync(async () => finalizer()).match(noop, (error) => {
178
- callbackResult.match(() => {
179
- throw error;
180
- }, () => {
181
- console.error(error);
182
- });
227
+ reportFinalizerError(callbackResult, error);
183
228
  });
184
229
  return callbackResult.match((value) => value, (error) => {
185
230
  throw error;
186
231
  });
187
232
  };
188
233
  //#endregion
234
+ //#region src/services/indexedDb/getRequestError.ts
235
+ const getRequestError = (request) => request.error ?? new DOMException("The request failed without an error", "UnknownError");
236
+ //#endregion
237
+ //#region src/services/indexedDb/getTransactionDone.ts
238
+ const getTransactionDone = (transaction) => new Promise((resolve, reject) => {
239
+ transaction.addEventListener("complete", () => {
240
+ resolve();
241
+ });
242
+ transaction.addEventListener("abort", () => {
243
+ reject(transaction.error ?? new DOMException("The transaction was aborted", "AbortError"));
244
+ });
245
+ });
246
+ //#endregion
247
+ //#region src/services/indexedDb/requestToPromise.ts
248
+ const requestToPromise = (request) => new Promise((resolve, reject) => {
249
+ request.addEventListener("success", () => {
250
+ resolve(request.result);
251
+ });
252
+ request.addEventListener("error", () => {
253
+ reject(getRequestError(request));
254
+ });
255
+ });
256
+ //#endregion
257
+ //#region src/services/indexedDb/wrapIndex.ts
258
+ const wrapIndex = (index) => ({
259
+ getAll: (query, count) => requestToPromise(index.getAll(query, count)),
260
+ getAllKeys: (query, count) => requestToPromise(index.getAllKeys(query, count))
261
+ });
262
+ //#endregion
263
+ //#region src/services/indexedDb/wrapObjectStore.ts
264
+ const wrapObjectStore = (objectStore) => {
265
+ const reader = {
266
+ get: (key) => requestToPromise(objectStore.get(key)),
267
+ getAll: (query, count) => requestToPromise(objectStore.getAll(query, count)),
268
+ getAllKeys: (query, count) => requestToPromise(objectStore.getAllKeys(query, count)),
269
+ index: (name) => wrapIndex(objectStore.index(name))
270
+ };
271
+ const writer = {
272
+ delete: (query) => requestToPromise(objectStore.delete(query)),
273
+ put: (value, key) => requestToPromise(objectStore.put(value, key))
274
+ };
275
+ const creator = { createIndex: (name, keyPath, options) => {
276
+ objectStore.createIndex(name, keyPath, options);
277
+ } };
278
+ return {
279
+ ...reader,
280
+ ...writer,
281
+ ...creator
282
+ };
283
+ };
284
+ //#endregion
285
+ //#region src/services/indexedDb/getTransactionObjectStore.ts
286
+ const getTransactionObjectStore = (transaction) => (name) => wrapObjectStore(transaction.objectStore(name));
287
+ //#endregion
288
+ //#region src/services/indexedDb/wrapTransaction.ts
289
+ const wrapTransaction = (transaction) => ({
290
+ done: getTransactionDone(transaction),
291
+ objectStore: getTransactionObjectStore(transaction)
292
+ });
293
+ //#endregion
294
+ //#region src/services/indexedDb/wrapDatabase.ts
295
+ const wrapDatabase = (database) => {
296
+ const getReadonlyObjectStore = (storeName) => wrapObjectStore(database.transaction(storeName, "readonly").objectStore(storeName));
297
+ const getReadwriteObjectStore = (storeName) => wrapObjectStore(database.transaction(storeName, "readwrite").objectStore(storeName));
298
+ const transaction = (storeNames, mode, options) => {
299
+ const names = typeof storeNames === "string" ? storeNames : [...storeNames];
300
+ return wrapTransaction(database.transaction(names, mode, options));
301
+ };
302
+ return {
303
+ close: () => {
304
+ database.close();
305
+ },
306
+ delete: (storeName, query) => getReadwriteObjectStore(storeName).delete(query),
307
+ get: (storeName, key) => getReadonlyObjectStore(storeName).get(key),
308
+ getAll: (storeName, query, count) => getReadonlyObjectStore(storeName).getAll(query, count),
309
+ getAllKeys: (storeName, query, count) => getReadonlyObjectStore(storeName).getAllKeys(query, count),
310
+ name: database.name,
311
+ put: (storeName, value, key) => getReadwriteObjectStore(storeName).put(value, key),
312
+ transaction
313
+ };
314
+ };
315
+ //#endregion
316
+ //#region src/services/indexedDb/wrapUpgradeDatabase.ts
317
+ const wrapUpgradeDatabase = (database) => ({
318
+ ...wrapDatabase(database),
319
+ createObjectStore: (name, options) => wrapObjectStore(database.createObjectStore(name, options))
320
+ });
321
+ //#endregion
322
+ //#region src/services/indexedDb/wrapUpgradeTransaction.ts
323
+ const wrapUpgradeTransaction = (transaction) => {
324
+ const done = getTransactionDone(transaction);
325
+ getResultAsync(() => done).match(noop, console.error);
326
+ return {
327
+ get done() {
328
+ return done;
329
+ },
330
+ objectStore: getTransactionObjectStore(transaction)
331
+ };
332
+ };
333
+ //#endregion
334
+ //#region src/services/indexedDb/openDatabase.ts
335
+ const openDatabase = (name, version, options = {}) => new Promise((resolve, reject) => {
336
+ const request = indexedDB.open(name, version);
337
+ request.addEventListener("blocked", (event) => {
338
+ options.blocked?.(event.oldVersion, event.newVersion);
339
+ });
340
+ request.addEventListener("upgradeneeded", (event) => {
341
+ const { transaction } = request;
342
+ if (!transaction) return;
343
+ getResult(() => options.upgrade?.(wrapUpgradeDatabase(request.result), event.oldVersion, event.newVersion, wrapUpgradeTransaction(transaction))).match(noop, (error) => {
344
+ console.error(error);
345
+ transaction.abort();
346
+ });
347
+ });
348
+ request.addEventListener("success", () => {
349
+ const database = request.result;
350
+ database.addEventListener("close", () => {
351
+ options.terminated?.();
352
+ });
353
+ database.addEventListener("versionchange", (event) => {
354
+ options.blocking?.(event.oldVersion, event.newVersion);
355
+ });
356
+ resolve(wrapDatabase(database));
357
+ });
358
+ request.addEventListener("error", () => {
359
+ reject(getRequestError(request));
360
+ });
361
+ });
362
+ //#endregion
189
363
  //#region src/services/message/constants.ts
190
364
  const MENTION_ID_ATTRIBUTE = "data-id";
191
365
  const MENTION_ITEM_TYPE_ATTRIBUTE = "data-mention-type";
@@ -197,35 +371,905 @@ const MENTION_HERE_ID = "@here";
197
371
  const MENTION_EVERYONE_ID = "@everyone";
198
372
  const CUSTOM_EMOJI_ID_ATTRIBUTE = "data-custom-emoji-id";
199
373
  const CUSTOM_EMOJI_NAME_ATTRIBUTE = "data-custom-emoji-name";
374
+ const SPOILER_ATTRIBUTE = "data-spoiler";
375
+ const SPOILER_SELECTOR = `span[${SPOILER_ATTRIBUTE}]`;
200
376
  //#endregion
201
377
  //#region src/services/message/getMentions.ts
202
378
  const getMentions = (message) => parse(message).querySelectorAll(MENTION_SELECTOR);
203
379
  //#endregion
380
+ //#region src/services/mime/constants.ts
381
+ const MEDIA_TYPE_REGEX = /^\s*(?<mediaType>[^;\s]*)(?:;|\s|$)/u;
382
+ const PATH_SEPARATOR_REGEX = /[/\\]/u;
383
+ const TEXT_MEDIA_TYPE_REGEX = /^text\//iu;
384
+ const CHARSET_PARAMETER_REGEX = /;\s*charset=/iu;
385
+ const DEFAULT_TEXT_CHARSET = "UTF-8";
386
+ const FacetScoreMap = /* @__PURE__ */ new Map([
387
+ ["prs.", 100],
388
+ ["vnd.", 400],
389
+ ["x-", 200],
390
+ ["x.", 300]
391
+ ]);
392
+ const DEFAULT_FACET_SCORE = 900;
393
+ const SourceScoreMap = /* @__PURE__ */ new Map([
394
+ ["apache", 20],
395
+ ["iana", 40],
396
+ ["nginx", 10]
397
+ ]);
398
+ const DEFAULT_SOURCE_SCORE = 30;
399
+ const TypeScoreMap = /* @__PURE__ */ new Map([
400
+ ["application", 1],
401
+ ["audio", 2],
402
+ ["font", 2],
403
+ ["video", 3]
404
+ ]);
405
+ const DEFAULT_TYPE_SCORE = 0;
406
+ //#endregion
407
+ //#region src/services/mime/getMediaType.ts
408
+ const getMediaType = (value) => MEDIA_TYPE_REGEX.exec(value)?.groups?.mediaType ?? "";
409
+ //#endregion
410
+ //#region src/services/mime/getMimeTypeEntryMap.ts
411
+ let mimeTypeEntryMap;
412
+ const getMimeTypeEntryMap = () => {
413
+ mimeTypeEntryMap ??= new Map(Object.entries(mimeDatabase));
414
+ return mimeTypeEntryMap;
415
+ };
416
+ //#endregion
417
+ //#region src/services/mime/charset.ts
418
+ const charset = (type) => {
419
+ const mediaType = getMediaType(type);
420
+ const dataCharset = getMimeTypeEntryMap().get(mediaType.toLowerCase())?.charset;
421
+ if (dataCharset) return dataCharset;
422
+ return TEXT_MEDIA_TYPE_REGEX.test(mediaType) ? DEFAULT_TEXT_CHARSET : false;
423
+ };
424
+ //#endregion
425
+ //#region src/services/mime/getMimeScore.ts
426
+ const getMimeScore = (mimeType, source = "") => {
427
+ if (mimeType === "application/octet-stream") return 0;
428
+ const [type = "", subtype = ""] = mimeType.split("/");
429
+ const facet = subtype.replace(/(?<prefix>\.|x-).*/u, "$<prefix>");
430
+ const facetScore = FacetScoreMap.get(facet) ?? 900;
431
+ const sourceScore = SourceScoreMap.get(source) ?? 30;
432
+ const typeScore = TypeScoreMap.get(type) ?? 0;
433
+ const lengthScore = 1 - mimeType.length / 100;
434
+ return facetScore + sourceScore + typeScore + lengthScore;
435
+ };
436
+ //#endregion
437
+ //#region src/services/mime/getExtensionMimeTypeMap.ts
438
+ let extensionMimeTypeMap;
439
+ const getPreferredMimeType = (currentMimeType, candidateMimeType) => {
440
+ if (currentMimeType === void 0) return candidateMimeType;
441
+ const entryMap = getMimeTypeEntryMap();
442
+ return getMimeScore(currentMimeType, entryMap.get(currentMimeType)?.source) > getMimeScore(candidateMimeType, entryMap.get(candidateMimeType)?.source) ? currentMimeType : candidateMimeType;
443
+ };
444
+ const getExtensionMimeTypeMap = () => {
445
+ if (!extensionMimeTypeMap) {
446
+ const map = /* @__PURE__ */ new Map();
447
+ for (const [mimeType, { extensions = [] }] of getMimeTypeEntryMap()) for (const extension of extensions) map.set(extension, getPreferredMimeType(map.get(extension), mimeType));
448
+ extensionMimeTypeMap = map;
449
+ }
450
+ return extensionMimeTypeMap;
451
+ };
452
+ //#endregion
453
+ //#region src/services/mime/lookup.ts
454
+ const getExtension = (path) => {
455
+ const name = path.split(PATH_SEPARATOR_REGEX).at(-1) ?? "";
456
+ const dotIndex = name.lastIndexOf(".");
457
+ if (path === name) return name.slice(dotIndex + 1);
458
+ return dotIndex > 0 ? name.slice(dotIndex + 1) : "";
459
+ };
460
+ const lookup = (path) => {
461
+ const extension = getExtension(path).toLowerCase();
462
+ if (!extension) return false;
463
+ return getExtensionMimeTypeMap().get(extension) ?? false;
464
+ };
465
+ //#endregion
466
+ //#region src/services/mime/contentType.ts
467
+ const contentType = (value) => {
468
+ const mediaType = value.includes("/") ? value : lookup(value);
469
+ if (!mediaType) return false;
470
+ if (CHARSET_PARAMETER_REGEX.test(mediaType)) return mediaType;
471
+ const mediaCharset = charset(mediaType);
472
+ return mediaCharset ? `${mediaType}; charset=${mediaCharset.toLowerCase()}` : mediaType;
473
+ };
474
+ //#endregion
475
+ //#region src/services/mime/extension.ts
476
+ const extension = (type) => getMimeTypeEntryMap().get(getMediaType(type).toLowerCase())?.extensions?.[0] ?? false;
477
+ //#endregion
204
478
  //#region src/services/prettier/css.ts
205
479
  const css = String.raw;
206
480
  //#endregion
207
481
  //#region src/services/prettier/html.ts
208
482
  const html = String.raw;
209
483
  //#endregion
210
- //#region src/services/sanitizeHtml/sanitizeHtml.ts
211
- const appendStyle = (style, declarations) => style ? `${style}; ${declarations}` : declarations;
212
- const transformCellAlign = (tagName, attribs) => {
213
- if (attribs.align) {
214
- attribs.style = appendStyle(attribs.style, `text-align:${attribs.align}`);
215
- delete attribs.align;
484
+ //#region src/services/profanity/englishProfaneWords.ts
485
+ const englishProfaneWords = [
486
+ "4r5e",
487
+ "5h1t",
488
+ "5hit",
489
+ "a55",
490
+ "anal",
491
+ "anus",
492
+ "ar5e",
493
+ "arrse",
494
+ "arse",
495
+ "arses",
496
+ "ass",
497
+ "ass-fucker",
498
+ "asses",
499
+ "assfucker",
500
+ "assfukka",
501
+ "asshole",
502
+ "assholes",
503
+ "asswhole",
504
+ "a_s_s",
505
+ "a$$",
506
+ "as$",
507
+ "a$s",
508
+ "b!tch",
509
+ "b00bs",
510
+ "b17ch",
511
+ "b1tch",
512
+ "ballbag",
513
+ "balls",
514
+ "ballsack",
515
+ "bastard",
516
+ "beastial",
517
+ "beastiality",
518
+ "bellend",
519
+ "bestial",
520
+ "bestiality",
521
+ "bi+ch",
522
+ "biatch",
523
+ "bitch",
524
+ "bitchboy",
525
+ "bitcher",
526
+ "bitchers",
527
+ "bitches",
528
+ "bitchin",
529
+ "bitching",
530
+ "bloody",
531
+ "blow job",
532
+ "blowjob",
533
+ "blowjobs",
534
+ "boiolas",
535
+ "bollock",
536
+ "bollok",
537
+ "boner",
538
+ "boob",
539
+ "boobs",
540
+ "booobs",
541
+ "boooobs",
542
+ "booooobs",
543
+ "booooooobs",
544
+ "breasts",
545
+ "buceta",
546
+ "bugger",
547
+ "bullshit",
548
+ "bum",
549
+ "butt",
550
+ "butts",
551
+ "butthole",
552
+ "buttmuch",
553
+ "buttplug",
554
+ "c0ck",
555
+ "c0cksucker",
556
+ "carpet muncher",
557
+ "cawk",
558
+ "chink",
559
+ "cipa",
560
+ "cl1t",
561
+ "clit",
562
+ "clitoris",
563
+ "clits",
564
+ "cnut",
565
+ "cock",
566
+ "cock-sucker",
567
+ "cockface",
568
+ "cockhead",
569
+ "cockmunch",
570
+ "cockmuncher",
571
+ "cocks",
572
+ "cocksuck",
573
+ "cocksucked",
574
+ "cocksucker",
575
+ "cocksucking",
576
+ "cocksucks",
577
+ "cocksuka",
578
+ "cocksukka",
579
+ "cok",
580
+ "cokmuncher",
581
+ "coksucka",
582
+ "coon",
583
+ "cox",
584
+ "crap",
585
+ "cum",
586
+ "cummer",
587
+ "cumming",
588
+ "cums",
589
+ "cumshot",
590
+ "cunilingus",
591
+ "cunillingus",
592
+ "cunnilingus",
593
+ "cunt",
594
+ "cuntlick",
595
+ "cuntlicker",
596
+ "cuntlicking",
597
+ "cunts",
598
+ "cyalis",
599
+ "cyberfuc",
600
+ "cyberfuck",
601
+ "cyberfucked",
602
+ "cyberfucker",
603
+ "cyberfuckers",
604
+ "cyberfucking",
605
+ "d1ck",
606
+ "damn",
607
+ "dick",
608
+ "dickhead",
609
+ "dildo",
610
+ "dildos",
611
+ "dink",
612
+ "dinks",
613
+ "dirsa",
614
+ "dlck",
615
+ "dog-fucker",
616
+ "doggin",
617
+ "dogging",
618
+ "donkeyribber",
619
+ "doosh",
620
+ "duche",
621
+ "dyke",
622
+ "ejaculate",
623
+ "ejaculated",
624
+ "ejaculates",
625
+ "ejaculating",
626
+ "ejaculatings",
627
+ "ejaculation",
628
+ "ejakulate",
629
+ "f u c k",
630
+ "f u c k e r",
631
+ "f4nny",
632
+ "fag",
633
+ "fagging",
634
+ "faggitt",
635
+ "faggot",
636
+ "faggs",
637
+ "fagot",
638
+ "fagots",
639
+ "fags",
640
+ "fanny",
641
+ "fannyflaps",
642
+ "fannyfucker",
643
+ "fanyy",
644
+ "fatass",
645
+ "fcuk",
646
+ "fcuker",
647
+ "fcuking",
648
+ "feck",
649
+ "fecker",
650
+ "felching",
651
+ "fellate",
652
+ "fellatio",
653
+ "fingerfuck",
654
+ "fingerfucked",
655
+ "fingerfucker",
656
+ "fingerfuckers",
657
+ "fingerfucking",
658
+ "fingerfucks",
659
+ "fistfuck",
660
+ "fistfucked",
661
+ "fistfucker",
662
+ "fistfuckers",
663
+ "fistfucking",
664
+ "fistfuckings",
665
+ "fistfucks",
666
+ "flange",
667
+ "fook",
668
+ "fooker",
669
+ "fuck",
670
+ "fucka",
671
+ "fucked",
672
+ "fucker",
673
+ "fuckers",
674
+ "fuckhead",
675
+ "fuckheads",
676
+ "fuckin",
677
+ "fucking",
678
+ "fuckings",
679
+ "fuckingshitmotherfucker",
680
+ "fuckme",
681
+ "fucks",
682
+ "fuckwhit",
683
+ "fuckwit",
684
+ "fudge packer",
685
+ "fudgepacker",
686
+ "fuk",
687
+ "fuker",
688
+ "fukker",
689
+ "fukkin",
690
+ "fuks",
691
+ "fukwhit",
692
+ "fukwit",
693
+ "fux",
694
+ "fux0r",
695
+ "f_u_c_k",
696
+ "gangbang",
697
+ "gangbanged",
698
+ "gangbangs",
699
+ "gaylord",
700
+ "gaysex",
701
+ "goatse",
702
+ "god-dam",
703
+ "god-damned",
704
+ "goddamn",
705
+ "goddamned",
706
+ "hardcoresex",
707
+ "headass",
708
+ "hoar",
709
+ "hoare",
710
+ "hoer",
711
+ "hoes",
712
+ "homo",
713
+ "hore",
714
+ "horniest",
715
+ "horny",
716
+ "hotsex",
717
+ "jack-off",
718
+ "jackoff",
719
+ "jap",
720
+ "jerk-off",
721
+ "jism",
722
+ "jiz",
723
+ "jizm",
724
+ "jizz",
725
+ "kawk",
726
+ "knobead",
727
+ "knobed",
728
+ "knobend",
729
+ "knobhead",
730
+ "knobjocky",
731
+ "knobjokey",
732
+ "kock",
733
+ "kondum",
734
+ "kondums",
735
+ "kum",
736
+ "kummer",
737
+ "kumming",
738
+ "kums",
739
+ "kunilingus",
740
+ "l3i+ch",
741
+ "l3itch",
742
+ "labia",
743
+ "lust",
744
+ "lusting",
745
+ "m0f0",
746
+ "m0fo",
747
+ "m45terbate",
748
+ "ma5terb8",
749
+ "ma5terbate",
750
+ "masochist",
751
+ "master-bate",
752
+ "masterb8",
753
+ "masterbat*",
754
+ "masterbat3",
755
+ "masterbate",
756
+ "masterbation",
757
+ "masterbations",
758
+ "masturbate",
759
+ "mo-fo",
760
+ "mof0",
761
+ "mofo",
762
+ "mothafuck",
763
+ "mothafucka",
764
+ "mothafuckas",
765
+ "mothafuckaz",
766
+ "mothafucked",
767
+ "mothafucker",
768
+ "mothafuckers",
769
+ "mothafuckin",
770
+ "mothafucking",
771
+ "mothafuckings",
772
+ "mothafucks",
773
+ "motherfuck",
774
+ "motherfucked",
775
+ "motherfucker",
776
+ "motherfuckers",
777
+ "motherfuckin",
778
+ "motherfucking",
779
+ "motherfuckings",
780
+ "motherfuckka",
781
+ "motherfucks",
782
+ "muff",
783
+ "muthafecker",
784
+ "muthafuckker",
785
+ "mutherfucker",
786
+ "n1gga",
787
+ "n1gger",
788
+ "nazi",
789
+ "nigg3r",
790
+ "nigg4h",
791
+ "nigga",
792
+ "niggah",
793
+ "niggas",
794
+ "niggaz",
795
+ "nigger",
796
+ "niggers",
797
+ "nob",
798
+ "nob jokey",
799
+ "nobhead",
800
+ "nobjocky",
801
+ "nobjokey",
802
+ "numbnuts",
803
+ "nutsack",
804
+ "orgasim",
805
+ "orgasims",
806
+ "orgasm",
807
+ "orgasms",
808
+ "p0rn",
809
+ "pawn",
810
+ "pecker",
811
+ "penis",
812
+ "penisfucker",
813
+ "phonesex",
814
+ "phuck",
815
+ "phuk",
816
+ "phuked",
817
+ "phuking",
818
+ "phukked",
819
+ "phukking",
820
+ "phuks",
821
+ "phuq",
822
+ "pigfucker",
823
+ "pimpis",
824
+ "piss",
825
+ "pissed",
826
+ "pisser",
827
+ "pissers",
828
+ "pisses",
829
+ "pissflaps",
830
+ "pissin",
831
+ "pissing",
832
+ "pissoff",
833
+ "poop",
834
+ "porn",
835
+ "porno",
836
+ "pornography",
837
+ "pornos",
838
+ "prick",
839
+ "pricks",
840
+ "pron",
841
+ "pube",
842
+ "pusse",
843
+ "pussi",
844
+ "pussies",
845
+ "pussy",
846
+ "pussys",
847
+ "rectum",
848
+ "retard",
849
+ "rimjaw",
850
+ "rimming",
851
+ "s hit",
852
+ "s.o.b.",
853
+ "sadist",
854
+ "schlong",
855
+ "screwing",
856
+ "scroat",
857
+ "scrote",
858
+ "scrotum",
859
+ "semen",
860
+ "sex",
861
+ "sh!+",
862
+ "sh!t",
863
+ "sh1t",
864
+ "shag",
865
+ "shagger",
866
+ "shaggin",
867
+ "shagging",
868
+ "shemale",
869
+ "shi+",
870
+ "shit",
871
+ "shitdick",
872
+ "shite",
873
+ "shited",
874
+ "shitey",
875
+ "shitfuck",
876
+ "shitfull",
877
+ "shithead",
878
+ "shiting",
879
+ "shitings",
880
+ "shits",
881
+ "shitted",
882
+ "shitter",
883
+ "shitters",
884
+ "shitting",
885
+ "shittings",
886
+ "shitty",
887
+ "skank",
888
+ "slut",
889
+ "sluts",
890
+ "smegma",
891
+ "smut",
892
+ "snatch",
893
+ "son-of-a-bitch",
894
+ "spac",
895
+ "spunk",
896
+ "s_h_i_t",
897
+ "t1tt1e5",
898
+ "t1tties",
899
+ "teets",
900
+ "teez",
901
+ "testical",
902
+ "testicle",
903
+ "tit",
904
+ "titfuck",
905
+ "tits",
906
+ "titt",
907
+ "tittie5",
908
+ "tittiefucker",
909
+ "titties",
910
+ "tittyfuck",
911
+ "tittywank",
912
+ "titwank",
913
+ "tosser",
914
+ "turd",
915
+ "tw4t",
916
+ "twat",
917
+ "twathead",
918
+ "twatty",
919
+ "twunt",
920
+ "twunter",
921
+ "v14gra",
922
+ "v1gra",
923
+ "vagina",
924
+ "viagra",
925
+ "vulva",
926
+ "w00se",
927
+ "wang",
928
+ "wank",
929
+ "wanker",
930
+ "wanky",
931
+ "whoar",
932
+ "whore",
933
+ "willies",
934
+ "willy"
935
+ ];
936
+ //#endregion
937
+ //#region src/services/profanity/checkContainsProfanity.ts
938
+ const WORD_CHARACTER_CLASS = String.raw`\p{L}\p{N}\p{M}`;
939
+ const PROFANE_WORD_ALTERNATION = englishProfaneWords.map((word) => word.replaceAll(/[.*+?^${}()|[\]\\]/gu, String.raw`\$&`)).join("|");
940
+ const WHOLE_WORD_PROFANITY_REGEX = new RegExp(`(?<![${WORD_CHARACTER_CLASS}])(?:${PROFANE_WORD_ALTERNATION})(?![${WORD_CHARACTER_CLASS}])`, "iu");
941
+ const SUBSTRING_PROFANITY_REGEX = new RegExp(PROFANE_WORD_ALTERNATION, "iu");
942
+ const checkContainsProfanity = (text, { isWholeWord = true } = {}) => {
943
+ if (typeof text !== "string") return false;
944
+ return (isWholeWord ? WHOLE_WORD_PROFANITY_REGEX : SUBSTRING_PROFANITY_REGEX).test(text);
945
+ };
946
+ //#endregion
947
+ //#region src/services/sanitizeHtml/checkIsWhitespaceCharacter.ts
948
+ const checkIsWhitespaceCharacter = (character) => character.trim() === "";
949
+ //#endregion
950
+ //#region src/services/sanitizeHtml/checkIsUnsafeUrlCharacter.ts
951
+ const FIRST_PRINTABLE_CODE_POINT = 32;
952
+ const DELETE_CODE_POINT = 127;
953
+ const LAST_C1_CONTROL_CODE_POINT = 159;
954
+ const GRAVE_ACCENT = "`";
955
+ const checkIsUnsafeUrlCharacter = (character) => {
956
+ const codePoint = character.codePointAt(0) ?? 0;
957
+ return checkIsWhitespaceCharacter(character) || codePoint < FIRST_PRINTABLE_CODE_POINT || codePoint >= DELETE_CODE_POINT && codePoint <= LAST_C1_CONTROL_CODE_POINT || character === GRAVE_ACCENT;
958
+ };
959
+ //#endregion
960
+ //#region src/util/array/takeOne.ts
961
+ const takeOne = (values, index = 0) => {
962
+ return values[index];
963
+ };
964
+ //#endregion
965
+ //#region src/services/sanitizeHtml/checkIsAllowedUrl.ts
966
+ const PATH_DELIMITER_REGEX = /[/?#]/u;
967
+ const NON_SCHEME_CHARACTERS_REGEX = /[^a-z\d+.-]/giu;
968
+ const SCHEME_SEPARATOR = ":";
969
+ const checkIsAllowedUrl = (url, allowedSchemes) => {
970
+ const normalizedUrl = url.split("").filter((character) => !checkIsUnsafeUrlCharacter(character)).join("");
971
+ const beforePath = takeOne(normalizedUrl.split(PATH_DELIMITER_REGEX), 0);
972
+ const separatorIndex = beforePath.indexOf(SCHEME_SEPARATOR);
973
+ if (separatorIndex === -1) return true;
974
+ const scheme = beforePath.slice(0, separatorIndex).replace(NON_SCHEME_CHARACTERS_REGEX, "").toLowerCase();
975
+ return allowedSchemes.includes(scheme);
976
+ };
977
+ //#endregion
978
+ //#region src/services/sanitizeHtml/constants.ts
979
+ const HTML_NAMESPACE = html$1.NS.HTML;
980
+ const DEFAULT_ALLOWED_TAGS = [
981
+ "address",
982
+ "article",
983
+ "aside",
984
+ "footer",
985
+ "header",
986
+ "h1",
987
+ "h2",
988
+ "h3",
989
+ "h4",
990
+ "h5",
991
+ "h6",
992
+ "hgroup",
993
+ "main",
994
+ "nav",
995
+ "section",
996
+ "blockquote",
997
+ "dd",
998
+ "div",
999
+ "dl",
1000
+ "dt",
1001
+ "figcaption",
1002
+ "figure",
1003
+ "hr",
1004
+ "li",
1005
+ "menu",
1006
+ "ol",
1007
+ "p",
1008
+ "pre",
1009
+ "ul",
1010
+ "a",
1011
+ "abbr",
1012
+ "b",
1013
+ "bdi",
1014
+ "bdo",
1015
+ "br",
1016
+ "cite",
1017
+ "code",
1018
+ "data",
1019
+ "dfn",
1020
+ "em",
1021
+ "i",
1022
+ "kbd",
1023
+ "mark",
1024
+ "q",
1025
+ "rb",
1026
+ "rp",
1027
+ "rt",
1028
+ "rtc",
1029
+ "ruby",
1030
+ "s",
1031
+ "samp",
1032
+ "small",
1033
+ "span",
1034
+ "strong",
1035
+ "sub",
1036
+ "sup",
1037
+ "time",
1038
+ "u",
1039
+ "var",
1040
+ "wbr",
1041
+ "caption",
1042
+ "col",
1043
+ "colgroup",
1044
+ "table",
1045
+ "tbody",
1046
+ "td",
1047
+ "tfoot",
1048
+ "th",
1049
+ "thead",
1050
+ "tr"
1051
+ ];
1052
+ const DEFAULT_LINK_ATTRIBUTES = [
1053
+ "href",
1054
+ "name",
1055
+ "target"
1056
+ ];
1057
+ const DEFAULT_ALLOWED_ATTRIBUTES = { a: DEFAULT_LINK_ATTRIBUTES };
1058
+ const DEFAULT_ALLOWED_SCHEMES = [
1059
+ "http",
1060
+ "https",
1061
+ "ftp",
1062
+ "mailto",
1063
+ "tel"
1064
+ ];
1065
+ const NON_TEXT_TAGS = [
1066
+ "iframe",
1067
+ "noembed",
1068
+ "noframes",
1069
+ "noscript",
1070
+ "option",
1071
+ "plaintext",
1072
+ "script",
1073
+ "style",
1074
+ "textarea",
1075
+ "title",
1076
+ "xmp"
1077
+ ];
1078
+ const VOID_TAGS = [
1079
+ "area",
1080
+ "base",
1081
+ "br",
1082
+ "col",
1083
+ "embed",
1084
+ "hr",
1085
+ "img",
1086
+ "input",
1087
+ "link",
1088
+ "meta",
1089
+ "source",
1090
+ "track",
1091
+ "wbr"
1092
+ ];
1093
+ const URL_ATTRIBUTES = [
1094
+ "action",
1095
+ "background",
1096
+ "cite",
1097
+ "data",
1098
+ "formaction",
1099
+ "href",
1100
+ "icon",
1101
+ "longdesc",
1102
+ "manifest",
1103
+ "poster",
1104
+ "src"
1105
+ ];
1106
+ const SRCSET_ATTRIBUTE = "srcset";
1107
+ const IMPORTANT_REGEX = /!\s*important$/iu;
1108
+ const MAX_NESTING_DEPTH = 256;
1109
+ const SRCSET_DESCRIPTOR_REGEX = /^(?:\d+w|\d*\.?\d+x|\d+h)$/u;
1110
+ const ESCAPED_TEXT_CHARACTERS_REGEX = /[&<>]/gu;
1111
+ const ESCAPED_ATTRIBUTE_CHARACTERS_REGEX = /[&"<>]/gu;
1112
+ const SANITIZER_ADVISORY_WATCH_SINCE = "2026-10-11";
1113
+ //#endregion
1114
+ //#region src/services/sanitizeHtml/getChildNodes.ts
1115
+ const getChildNodes = (element) => "content" in element ? element.content.childNodes : element.childNodes;
1116
+ //#endregion
1117
+ //#region src/services/sanitizeHtml/collectText.ts
1118
+ const collectText = (nodes, depth) => depth > 256 ? "" : nodes.map((node) => {
1119
+ if ("value" in node) return node.value;
1120
+ if (!("tagName" in node) || NON_TEXT_TAGS.includes(node.tagName)) return "";
1121
+ return collectText(getChildNodes(node), depth + 1);
1122
+ }).join("");
1123
+ //#endregion
1124
+ //#region src/services/sanitizeHtml/escapeCharacters.ts
1125
+ const NON_BREAKING_SPACE = String.fromCodePoint(160);
1126
+ const escapeCharacters = (value, charactersRegex, entities) => value.replace(charactersRegex, (character) => entities[character] ?? character).replaceAll(NON_BREAKING_SPACE, "&nbsp;");
1127
+ //#endregion
1128
+ //#region src/services/sanitizeHtml/escapeAttribute.ts
1129
+ const ESCAPED_ATTRIBUTE_CHARACTERS = {
1130
+ "\"": "&quot;",
1131
+ "&": "&amp;",
1132
+ "<": "&lt;",
1133
+ ">": "&gt;"
1134
+ };
1135
+ const escapeAttribute = (value) => escapeCharacters(value, ESCAPED_ATTRIBUTE_CHARACTERS_REGEX, ESCAPED_ATTRIBUTE_CHARACTERS);
1136
+ //#endregion
1137
+ //#region src/services/sanitizeHtml/escapeText.ts
1138
+ const ESCAPED_TEXT_CHARACTERS = {
1139
+ "&": "&amp;",
1140
+ "<": "&lt;",
1141
+ ">": "&gt;"
1142
+ };
1143
+ const escapeText = (text) => escapeCharacters(text, ESCAPED_TEXT_CHARACTERS_REGEX, ESCAPED_TEXT_CHARACTERS);
1144
+ //#endregion
1145
+ //#region src/services/sanitizeHtml/matchesClassPattern.ts
1146
+ const matchesClassPattern = (className, pattern) => pattern.endsWith("*") ? className.startsWith(pattern.slice(0, -1)) : className === pattern;
1147
+ //#endregion
1148
+ //#region src/services/sanitizeHtml/filterClasses.ts
1149
+ const filterClasses = (value, patterns) => {
1150
+ if (!patterns) return void 0;
1151
+ const classNames = value.split(/\s+/u).filter((className) => className && patterns.some((pattern) => matchesClassPattern(className, pattern)));
1152
+ return classNames.length > 0 ? classNames.join(" ") : void 0;
1153
+ };
1154
+ //#endregion
1155
+ //#region src/services/sanitizeHtml/filterSrcset.ts
1156
+ const COMMA = ",";
1157
+ const OPENING_PARENTHESIS = "(";
1158
+ const CLOSING_PARENTHESIS = ")";
1159
+ const filterSrcset = (value, allowedSchemes) => {
1160
+ const candidates = [];
1161
+ let position = 0;
1162
+ while (position < value.length) {
1163
+ while (position < value.length && (checkIsWhitespaceCharacter(value.charAt(position)) || value.charAt(position) === COMMA)) position++;
1164
+ const urlStart = position;
1165
+ while (position < value.length && !checkIsWhitespaceCharacter(value.charAt(position))) position++;
1166
+ let url = value.slice(urlStart, position);
1167
+ let descriptorText = "";
1168
+ if (url.endsWith(COMMA)) url = url.replace(/,+$/u, "");
1169
+ else {
1170
+ const descriptorStart = position;
1171
+ let isInParentheses = false;
1172
+ while (position < value.length && (isInParentheses || value.charAt(position) !== COMMA)) {
1173
+ if (value.charAt(position) === OPENING_PARENTHESIS) isInParentheses = true;
1174
+ else if (value.charAt(position) === CLOSING_PARENTHESIS) isInParentheses = false;
1175
+ position++;
1176
+ }
1177
+ descriptorText = value.slice(descriptorStart, position);
1178
+ position++;
1179
+ }
1180
+ const descriptors = descriptorText.trim().split(/\s+/u).filter(Boolean);
1181
+ if (!url || !checkIsAllowedUrl(url, allowedSchemes)) continue;
1182
+ if (descriptors.length > 1 || descriptors.some((descriptor) => !SRCSET_DESCRIPTOR_REGEX.test(descriptor))) continue;
1183
+ candidates.push([url, ...descriptors].join(" "));
216
1184
  }
217
- return {
218
- attribs,
219
- tagName
220
- };
1185
+ return candidates.length > 0 ? candidates.join(", ") : void 0;
221
1186
  };
222
- const transformLink = (tagName, attribs) => ({
223
- attribs: {
224
- ...attribs,
225
- rel: "noopener noreferrer nofollow",
226
- target: "_blank"
227
- },
228
- tagName
1187
+ //#endregion
1188
+ //#region src/services/sanitizeHtml/filterStyle.ts
1189
+ const DECLARATION_SEPARATOR = ";";
1190
+ const PROPERTY_SEPARATOR = ":";
1191
+ const IMPORTANT_SUFFIX = "!important";
1192
+ const filterStyle = (value, rules) => {
1193
+ if (!rules) return void 0;
1194
+ const declarations = /* @__PURE__ */ new Map();
1195
+ for (const declaration of value.split(DECLARATION_SEPARATOR)) {
1196
+ const separatorIndex = declaration.indexOf(PROPERTY_SEPARATOR);
1197
+ if (separatorIndex === -1) continue;
1198
+ const property = declaration.slice(0, separatorIndex).trim().toLowerCase();
1199
+ if (!Object.hasOwn(rules, property)) continue;
1200
+ const rawValue = declaration.slice(separatorIndex + 1).trim();
1201
+ const important = IMPORTANT_REGEX.test(rawValue);
1202
+ const propertyValue = rawValue.replace(IMPORTANT_REGEX, "").trim();
1203
+ if (!(rules[property] ?? []).some((rule) => rule.test(propertyValue))) continue;
1204
+ if (declarations.get(property)?.important && !important) continue;
1205
+ declarations.set(property, {
1206
+ important,
1207
+ propertyValue
1208
+ });
1209
+ }
1210
+ if (declarations.size === 0) return void 0;
1211
+ return Array.from(declarations, ([property, { important, propertyValue }]) => `${property}${PROPERTY_SEPARATOR}${propertyValue}${important ? IMPORTANT_SUFFIX : ""}`).join(DECLARATION_SEPARATOR);
1212
+ };
1213
+ //#endregion
1214
+ //#region src/services/sanitizeHtml/filterAttributes.ts
1215
+ const getTagPolicy = (tagPolicies, tagName) => Object.hasOwn(tagPolicies, tagName) ? tagPolicies[tagName] : void 0;
1216
+ const filterAttributes = (element, policy) => {
1217
+ const { tagName } = element;
1218
+ const allowedAttributes = getTagPolicy(policy.allowedAttributes, tagName) ?? [];
1219
+ const isClassAllowed = Object.hasOwn(policy.allowedClasses, tagName);
1220
+ const parsedAttributes = Object.fromEntries(element.attrs.map(({ name, value }) => [name, value]));
1221
+ const transform = getTagPolicy(policy.transformAttributes, tagName);
1222
+ const attributes = transform ? transform(parsedAttributes) : parsedAttributes;
1223
+ const kept = {};
1224
+ for (const [name, value] of Object.entries(attributes)) {
1225
+ if (name === "class" ? !isClassAllowed : !allowedAttributes.includes(name)) continue;
1226
+ const filteredValue = filterValue(tagName, name, value, policy);
1227
+ if (filteredValue !== void 0) kept[name] = filteredValue;
1228
+ }
1229
+ return kept;
1230
+ };
1231
+ const filterValue = (tagName, name, value, policy) => {
1232
+ if (name === "style") return filterStyle(value, getTagPolicy(policy.allowedStyles, tagName));
1233
+ if (name === "class") return filterClasses(value, getTagPolicy(policy.allowedClasses, tagName));
1234
+ if (name === "srcset") return filterSrcset(value, policy.allowedSchemes);
1235
+ if (URL_ATTRIBUTES.includes(name)) return checkIsAllowedUrl(value, policy.allowedSchemes) ? value : void 0;
1236
+ return value;
1237
+ };
1238
+ //#endregion
1239
+ //#region src/services/sanitizeHtml/renderNode.ts
1240
+ const renderNode = (node, policy, depth) => {
1241
+ if (node.nodeName === "#text") return escapeText(node.value);
1242
+ if (!("tagName" in node) || depth > 256) return "";
1243
+ const element = node;
1244
+ const children = getChildNodes(element).map((child) => renderNode(child, policy, depth + 1)).join("");
1245
+ if (!(element.namespaceURI === HTML_NAMESPACE && !NON_TEXT_TAGS.includes(element.tagName) && policy.allowedTags.includes(element.tagName))) return NON_TEXT_TAGS.includes(element.tagName) ? "" : children;
1246
+ const attributes = Object.entries(filterAttributes(element, policy)).map(([name, value]) => ` ${name}="${escapeAttribute(value)}"`).join("");
1247
+ const opening = `<${element.tagName}${attributes}>`;
1248
+ return VOID_TAGS.includes(element.tagName) ? opening : `${opening}${children}</${element.tagName}>`;
1249
+ };
1250
+ //#endregion
1251
+ //#region src/services/sanitizeHtml/filterHtml.ts
1252
+ const filterHtml = (html, policy) => {
1253
+ const context = defaultTreeAdapter.createElement("body", HTML_NAMESPACE, []);
1254
+ const childNodes = parseFragment(context, html, {}).childNodes;
1255
+ const output = childNodes.map((node) => renderNode(node, policy, 0)).join("");
1256
+ return parseFragment(context, output, {}).childNodes.map((node) => renderNode(node, policy, 0)).join("") === output ? output : escapeText(collectText(childNodes, 0));
1257
+ };
1258
+ //#endregion
1259
+ //#region src/services/sanitizeHtml/sanitizeHtml.ts
1260
+ const appendStyle = (style, declarations) => style ? `${style}; ${declarations}` : declarations;
1261
+ const transformCellAlign = ({ align, ...attributes }) => align ? {
1262
+ ...attributes,
1263
+ style: appendStyle(attributes.style, `text-align:${align}`)
1264
+ } : attributes;
1265
+ const transformLink = (attributes) => ({
1266
+ ...attributes,
1267
+ rel: "noopener noreferrer nofollow",
1268
+ target: "_blank"
1269
+ });
1270
+ const transformTable = (attributes) => ({
1271
+ ...attributes,
1272
+ style: appendStyle(attributes.style, "width:100%; border-collapse: collapse;")
229
1273
  });
230
1274
  const TEXT_ALIGN_REGEXES = [/^(?:left|right|center|justify)$/u];
231
1275
  const TABLE_ALLOWED_STYLES = {
@@ -236,33 +1280,30 @@ const TABLE_ALLOWED_STYLES = {
236
1280
  td: { "text-align": TEXT_ALIGN_REGEXES },
237
1281
  th: { "text-align": TEXT_ALIGN_REGEXES }
238
1282
  };
239
- const sanitizeHtml = (...[html, options]) => baseSanitizeHtml(html, {
240
- ...options,
1283
+ const sanitizeHtml = (html, options) => filterHtml(html, {
241
1284
  allowedAttributes: {
242
- ...options?.allowedAttributes || baseSanitizeHtml.defaults.allowedAttributes,
243
- a: [
1285
+ ...options?.allowedAttributes ?? DEFAULT_ALLOWED_ATTRIBUTES,
1286
+ a: [.../* @__PURE__ */ new Set([
1287
+ ...options?.allowedAttributes?.a ?? DEFAULT_LINK_ATTRIBUTES,
244
1288
  "href",
245
1289
  "rel",
246
1290
  "target"
247
- ],
1291
+ ])],
248
1292
  table: ["style"],
249
1293
  td: ["style"],
250
1294
  th: ["style"]
251
1295
  },
1296
+ allowedClasses: options?.allowedClasses ?? {},
1297
+ allowedSchemes: DEFAULT_ALLOWED_SCHEMES,
252
1298
  allowedStyles: {
253
1299
  ...options?.allowedStyles,
254
1300
  ...TABLE_ALLOWED_STYLES
255
1301
  },
256
- transformTags: {
257
- ...options?.transformTags,
1302
+ allowedTags: options?.allowedTags ?? DEFAULT_ALLOWED_TAGS,
1303
+ transformAttributes: {
1304
+ ...options?.transformAttributes,
258
1305
  a: transformLink,
259
- table: (tagName, attribs) => ({
260
- attribs: {
261
- ...attribs,
262
- style: appendStyle(attribs.style, "width:100%; border-collapse: collapse;")
263
- },
264
- tagName
265
- }),
1306
+ table: transformTable,
266
1307
  td: transformCellAlign,
267
1308
  th: transformCellAlign
268
1309
  }
@@ -276,22 +1317,20 @@ const COLOR_REGEXES = [
276
1317
  ];
277
1318
  const sanitizeTextHtml = (html) => sanitizeHtml(html, {
278
1319
  allowedAttributes: {
279
- code: ["class"],
280
1320
  input: [
281
1321
  "checked",
282
1322
  "disabled",
283
1323
  "type"
284
1324
  ],
285
1325
  li: ["data-checked", "data-type"],
286
- pre: ["class"],
287
1326
  span: [
288
- "class",
289
1327
  CUSTOM_EMOJI_ID_ATTRIBUTE,
290
1328
  CUSTOM_EMOJI_NAME_ATTRIBUTE,
291
1329
  MENTION_ID_ATTRIBUTE,
292
1330
  MENTION_ITEM_TYPE_ATTRIBUTE,
293
1331
  MENTION_LABEL_ATTRIBUTE,
294
1332
  MENTION_TYPE_ATTRIBUTE,
1333
+ SPOILER_ATTRIBUTE,
295
1334
  "style"
296
1335
  ],
297
1336
  ul: ["data-type"]
@@ -307,21 +1346,15 @@ const sanitizeTextHtml = (html) => sanitizeHtml(html, {
307
1346
  color: COLOR_REGEXES
308
1347
  } },
309
1348
  allowedTags: [
310
- ...baseSanitizeHtml.defaults.allowedTags,
1349
+ ...DEFAULT_ALLOWED_TAGS,
311
1350
  "input",
312
1351
  "label"
313
1352
  ],
314
- transformTags: { input: (tagName, { checked }) => {
315
- const attribs = {
316
- disabled: "",
317
- type: "checkbox"
318
- };
319
- if (checked !== void 0) attribs.checked = checked;
320
- return {
321
- attribs,
322
- tagName
323
- };
324
- } }
1353
+ transformAttributes: { input: ({ checked }) => ({
1354
+ ...checked === void 0 ? {} : { checked },
1355
+ disabled: "",
1356
+ type: "checkbox"
1357
+ }) }
325
1358
  });
326
1359
  //#endregion
327
1360
  //#region src/services/shared/applyItemMetadataMixin.ts
@@ -424,11 +1457,6 @@ const chunkBySerializedSize = (items, maxBytes, maxCount) => {
424
1457
  return chunks;
425
1458
  };
426
1459
  //#endregion
427
- //#region src/util/array/takeOne.ts
428
- const takeOne = (values, index = 0) => {
429
- return values[index];
430
- };
431
- //#endregion
432
1460
  //#region src/util/date/getZonedDateTime.ts
433
1461
  const getZonedDateTime = (date) => Temporal.Instant.fromEpochMilliseconds(date.getTime()).toZonedDateTimeISO(Temporal.Now.timeZoneId());
434
1462
  //#endregion
@@ -496,6 +1524,57 @@ const getOrCreate = (map, key, create) => {
496
1524
  return value;
497
1525
  };
498
1526
  //#endregion
1527
+ //#region src/util/object/checkIsCustomMethod.ts
1528
+ const checkIsCustomMethod = (value, methodName) => {
1529
+ const method = Reflect.get(value, methodName);
1530
+ return typeof method === "function" && method !== Object.prototype[methodName];
1531
+ };
1532
+ //#endregion
1533
+ //#region src/util/object/checkIsSameBytes.ts
1534
+ const toBytes = (view) => ArrayBuffer.isView(view) ? new Uint8Array(view.buffer, view.byteOffset, view.byteLength) : new Uint8Array(view);
1535
+ const checkIsSameBytes = (first, second) => {
1536
+ const firstBytes = toBytes(first);
1537
+ const secondBytes = toBytes(second);
1538
+ return firstBytes.length === secondBytes.length && firstBytes.every((byte, index) => byte === secondBytes[index]);
1539
+ };
1540
+ //#endregion
1541
+ //#region src/util/object/checkIsSameValueZero.ts
1542
+ const checkIsSameValueZero = (first, second) => first === second || Number.isNaN(first) && Number.isNaN(second);
1543
+ //#endregion
1544
+ //#region src/util/object/getEnumerableKeys.ts
1545
+ const getEnumerableKeys = (value) => Reflect.ownKeys(value).filter((key) => Object.prototype.propertyIsEnumerable.call(value, key));
1546
+ //#endregion
1547
+ //#region src/util/object/checkIsDeepEqual.ts
1548
+ const checkIsBinary = (value) => ArrayBuffer.isView(value) || value instanceof ArrayBuffer || typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer;
1549
+ const checkIsDeepEqual = (first, second) => {
1550
+ if (first === second) return true;
1551
+ if (typeof first !== "object" || typeof second !== "object" || first === null || second === null) return checkIsSameValueZero(first, second);
1552
+ if (Object.getPrototypeOf(first) !== Object.getPrototypeOf(second)) return false;
1553
+ if (Array.isArray(first) || Array.isArray(second)) {
1554
+ if (!Array.isArray(first) || !Array.isArray(second) || first.length !== second.length) return false;
1555
+ for (const [index, item] of first.entries()) if (!checkIsDeepEqual(item, second[index])) return false;
1556
+ return true;
1557
+ }
1558
+ if (checkIsBinary(first) && checkIsBinary(second)) return checkIsSameBytes(first, second);
1559
+ if (first instanceof RegExp && second instanceof RegExp) return first.source === second.source && first.flags === second.flags;
1560
+ if (first instanceof WeakMap || first instanceof WeakSet || first instanceof Promise || first instanceof Blob) return false;
1561
+ if (checkIsCustomMethod(first, "valueOf") && checkIsCustomMethod(second, "valueOf")) return checkIsSameValueZero(first.valueOf(), second.valueOf());
1562
+ if (checkIsCustomMethod(first, "toString") && checkIsCustomMethod(second, "toString")) return first.toString() === second.toString();
1563
+ if (first instanceof Map && second instanceof Map) {
1564
+ if (first.size !== second.size) return false;
1565
+ for (const [key, value] of first) if (!second.has(key) || !checkIsDeepEqual(value, second.get(key))) return false;
1566
+ return true;
1567
+ }
1568
+ if (first instanceof Set && second instanceof Set) {
1569
+ if (first.size !== second.size) return false;
1570
+ for (const value of first) if (!second.has(value)) return false;
1571
+ return true;
1572
+ }
1573
+ const firstKeys = getEnumerableKeys(first);
1574
+ if (firstKeys.length !== getEnumerableKeys(second).length) return false;
1575
+ return firstKeys.every((key) => Object.prototype.propertyIsEnumerable.call(second, key) && checkIsDeepEqual(Reflect.get(first, key), Reflect.get(second, key)));
1576
+ };
1577
+ //#endregion
499
1578
  //#region src/util/object/checkIsPlainObject.ts
500
1579
  const checkIsPlainObject = (data) => {
501
1580
  if (typeof data !== "object" || data === null) return false;
@@ -521,6 +1600,31 @@ const jsonDateParse = (text) => JSON.parse(text, (_key, value) => {
521
1600
  //#region src/util/object/mergeObjectsStrict.ts
522
1601
  const mergeObjectsStrict = (...objects) => Object.assign({}, ...objects);
523
1602
  //#endregion
1603
+ //#region src/util/object/omitDeep.ts
1604
+ const checkIsWalkable = (value) => Object.prototype.toString.call(value) === "[object Object]";
1605
+ const omitValue = (value, omittedKeys) => {
1606
+ if (Array.isArray(value)) return value.map((element) => omitValue(element, omittedKeys));
1607
+ if (!checkIsWalkable(value)) return value;
1608
+ const omittedValue = {};
1609
+ for (const [key, propertyValue] of Object.entries(value)) if (!omittedKeys.has(key)) omittedValue[key] = omitValue(propertyValue, omittedKeys);
1610
+ return omittedValue;
1611
+ };
1612
+ const omitDeep = (value, ...keys) => omitValue(value, new Set(keys));
1613
+ //#endregion
1614
+ //#region src/util/promise/createEvictingPromiseCache.ts
1615
+ const createEvictingPromiseCache = (getKey, load) => {
1616
+ const promiseMap = /* @__PURE__ */ new Map();
1617
+ return (...args) => {
1618
+ const key = getKey(...args);
1619
+ const promise = promiseMap.get(key) ?? load(...args);
1620
+ promiseMap.set(key, promise);
1621
+ return getResultAsync(() => promise).match((value) => value, (error) => {
1622
+ if (promiseMap.get(key) === promise) promiseMap.delete(key);
1623
+ throw error;
1624
+ });
1625
+ };
1626
+ };
1627
+ //#endregion
524
1628
  //#region src/util/promise/settleAll.ts
525
1629
  const settleAll = async (tasks, concurrencyLimit = tasks.length) => {
526
1630
  if (tasks.length === 0) return [];
@@ -539,6 +1643,206 @@ const settleAll = async (tasks, concurrencyLimit = tasks.length) => {
539
1643
  //#region src/util/text/capitalize.ts
540
1644
  const capitalize = (string) => `${string.charAt(0).toUpperCase()}${string.slice(1)}`;
541
1645
  //#endregion
1646
+ //#region src/util/text/dedent.ts
1647
+ const ESCAPE_CHARACTER = "\\";
1648
+ const LINE_FEED = "\n";
1649
+ const LINE_FEED_CHARACTER = {
1650
+ escapable: false,
1651
+ value: LINE_FEED
1652
+ };
1653
+ const HEXADECIMAL_REGEX = /^[\da-fA-F]$/u;
1654
+ const WHITESPACE_REGEX = /^\s$/u;
1655
+ const BRACED_CODE_POINT_MAXIMUM_DIGITS = 6;
1656
+ const CODE_POINT_MAXIMUM = 1114111;
1657
+ const HEXADECIMAL_BYTE_DIGITS = 2;
1658
+ const HEXADECIMAL_UNIT_DIGITS = 4;
1659
+ const escapeValueMap = {
1660
+ "0": "\0",
1661
+ $: "$",
1662
+ "\\": "\\",
1663
+ "`": "`",
1664
+ b: "\b",
1665
+ f: "\f",
1666
+ n: "\n",
1667
+ r: "\r",
1668
+ t: " ",
1669
+ v: "\v",
1670
+ "{": "{"
1671
+ };
1672
+ const toCharacters = (text, escapable) => text.split("").map((value) => ({
1673
+ escapable,
1674
+ value
1675
+ }));
1676
+ const isWhitespace = (character) => WHITESPACE_REGEX.test(character.value);
1677
+ const alignValue = (value, precedingText) => {
1678
+ const currentLine = precedingText.slice(precedingText.lastIndexOf(LINE_FEED) + 1);
1679
+ const indentation = /^\s+/u.exec(currentLine)?.[0];
1680
+ return indentation ? value.replaceAll(LINE_FEED, `${LINE_FEED}${indentation}`) : value;
1681
+ };
1682
+ const isEscapeStart = (characters, index) => {
1683
+ const character = characters[index];
1684
+ const next = characters[index + 1];
1685
+ return character?.escapable === true && character.value === ESCAPE_CHARACTER && next?.escapable === true;
1686
+ };
1687
+ const removeLineContinuations = (characters) => {
1688
+ const result = [];
1689
+ let index = 0;
1690
+ while (index < characters.length) {
1691
+ const character = characters[index];
1692
+ if (!character) break;
1693
+ if (isEscapeStart(characters, index)) {
1694
+ const next = characters[index + 1];
1695
+ if (next?.value === LINE_FEED) {
1696
+ index += 2;
1697
+ while (characters[index]?.escapable === true && (characters[index]?.value === " " || characters[index]?.value === " ")) index++;
1698
+ } else {
1699
+ result.push(character, ...next ? [next] : []);
1700
+ index += 2;
1701
+ }
1702
+ } else {
1703
+ result.push(character);
1704
+ index++;
1705
+ }
1706
+ }
1707
+ return result;
1708
+ };
1709
+ const splitLines = (characters) => {
1710
+ const lines = [];
1711
+ let line = [];
1712
+ for (const character of characters) if (character.value === LINE_FEED) {
1713
+ lines.push(line);
1714
+ line = [];
1715
+ } else line.push(character);
1716
+ lines.push(line);
1717
+ return lines;
1718
+ };
1719
+ const getIndentation = (line) => {
1720
+ const indentation = line.findIndex((character) => !isWhitespace(character));
1721
+ return indentation > 0 ? indentation : void 0;
1722
+ };
1723
+ const dedentCharacters = (characters) => {
1724
+ const lines = splitLines(characters);
1725
+ const indentations = lines.map((line) => getIndentation(line)).filter((indentation) => indentation !== void 0);
1726
+ if (indentations.length === 0) return characters;
1727
+ const minimumIndentation = Math.min(...indentations);
1728
+ const result = [];
1729
+ for (const [index, line] of lines.entries()) {
1730
+ if (index > 0) result.push(LINE_FEED_CHARACTER);
1731
+ const first = line[0]?.value;
1732
+ result.push(...first === " " || first === " " ? line.slice(minimumIndentation) : line);
1733
+ }
1734
+ return result;
1735
+ };
1736
+ const trimCharacters = (characters) => {
1737
+ const start = characters.findIndex((character) => !isWhitespace(character));
1738
+ if (start === -1) return [];
1739
+ return characters.slice(start, characters.findLastIndex((character) => !isWhitespace(character)) + 1);
1740
+ };
1741
+ const readHexadecimal = (characters, start, digits) => {
1742
+ let hexadecimal = "";
1743
+ for (let index = start; index < start + digits; index++) {
1744
+ const character = characters[index];
1745
+ if (character?.escapable !== true || !HEXADECIMAL_REGEX.test(character.value)) return void 0;
1746
+ hexadecimal += character.value;
1747
+ }
1748
+ return hexadecimal;
1749
+ };
1750
+ const readBracedCodePoint = (characters, index) => {
1751
+ if (characters[index + 2]?.value !== "{") return void 0;
1752
+ let digits = "";
1753
+ let cursor = index + 3;
1754
+ while (digits.length < BRACED_CODE_POINT_MAXIMUM_DIGITS && HEXADECIMAL_REGEX.test(characters[cursor]?.value ?? "")) {
1755
+ digits += characters[cursor]?.value;
1756
+ cursor++;
1757
+ }
1758
+ const closing = characters[cursor];
1759
+ if (digits.length === 0 || closing?.escapable !== true || closing.value !== "}") return void 0;
1760
+ const codePoint = Number.parseInt(digits, 16);
1761
+ if (codePoint > CODE_POINT_MAXIMUM) return void 0;
1762
+ return {
1763
+ length: cursor - index + 1,
1764
+ text: String.fromCodePoint(codePoint)
1765
+ };
1766
+ };
1767
+ const fromHexadecimal = (hexadecimal) => String.fromCodePoint(Number.parseInt(hexadecimal, 16));
1768
+ const readEscape = (characters, index) => {
1769
+ const character = characters[index];
1770
+ if (!character) return {
1771
+ length: 0,
1772
+ text: ""
1773
+ };
1774
+ if (!isEscapeStart(characters, index)) return {
1775
+ length: 1,
1776
+ text: character.value
1777
+ };
1778
+ const next = characters[index + 1];
1779
+ const escapeValue = next ? escapeValueMap[next.value] : void 0;
1780
+ if (escapeValue !== void 0) return {
1781
+ length: 2,
1782
+ text: escapeValue
1783
+ };
1784
+ if (next?.value === "x") {
1785
+ const hexadecimal = readHexadecimal(characters, index + 2, HEXADECIMAL_BYTE_DIGITS);
1786
+ if (hexadecimal !== void 0) return {
1787
+ length: 4,
1788
+ text: fromHexadecimal(hexadecimal)
1789
+ };
1790
+ }
1791
+ if (next?.value === "u") {
1792
+ const braced = readBracedCodePoint(characters, index);
1793
+ if (braced) return braced;
1794
+ const hexadecimal = readHexadecimal(characters, index + 2, HEXADECIMAL_UNIT_DIGITS);
1795
+ if (hexadecimal !== void 0) return {
1796
+ length: 6,
1797
+ text: fromHexadecimal(hexadecimal)
1798
+ };
1799
+ }
1800
+ return {
1801
+ length: 1,
1802
+ text: character.value
1803
+ };
1804
+ };
1805
+ const cookCharacters = (characters) => {
1806
+ let result = "";
1807
+ let index = 0;
1808
+ while (index < characters.length) {
1809
+ const cooked = readEscape(characters, index);
1810
+ result += cooked.text;
1811
+ index += cooked.length;
1812
+ }
1813
+ return result;
1814
+ };
1815
+ const createDedent = (options) => {
1816
+ const dedent = (strings, ...values) => {
1817
+ const isTemplate = typeof strings !== "string";
1818
+ const raws = isTemplate ? strings.raw : [strings];
1819
+ const { alignValues = false, escapeSpecialCharacters = isTemplate, trimWhitespace = true } = options;
1820
+ let precedingText = "";
1821
+ const parts = [];
1822
+ for (const [index, raw] of raws.entries()) {
1823
+ parts.push(toCharacters(raw, true));
1824
+ precedingText += raw;
1825
+ if (index < values.length) {
1826
+ const value = String(values[index]);
1827
+ const alignedValue = alignValues ? alignValue(value, precedingText) : value;
1828
+ parts.push(toCharacters(alignedValue, false));
1829
+ precedingText += alignedValue;
1830
+ }
1831
+ }
1832
+ let characters = parts.flat();
1833
+ if (escapeSpecialCharacters) characters = removeLineContinuations(characters);
1834
+ characters = dedentCharacters(characters);
1835
+ if (trimWhitespace) characters = trimCharacters(characters);
1836
+ return escapeSpecialCharacters ? cookCharacters(characters) : characters.map((character) => character.value).join("");
1837
+ };
1838
+ dedent.withOptions = (newOptions) => createDedent({
1839
+ ...options,
1840
+ ...newOptions
1841
+ });
1842
+ return dedent;
1843
+ };
1844
+ const dedent = createDedent({});
1845
+ //#endregion
542
1846
  //#region src/util/text/encodeUrlSubDelimiters.ts
543
1847
  const EncodedSubDelimiterMap = {
544
1848
  "!": "%21",
@@ -611,4 +1915,4 @@ const exhaustiveGuard = (value) => {
611
1915
  throw new InvalidOperationError("Read", exhaustiveGuard.name, JSON.stringify(value));
612
1916
  };
613
1917
  //#endregion
614
- export { ALL_SPECIAL_VALUES, CUSTOM_EMOJI_ID_ATTRIBUTE, CUSTOM_EMOJI_NAME_ATTRIBUTE, DEFAULT_COMPRESSION_LEVEL, ForbiddenError, GIBIBYTE, ID_SEPARATOR, InvalidOperationError, ItemMetadata, KIBIBYTE, MAX_READ_LIMIT, MAX_WINDOW_LOG, MENTION_EVERYONE_ID, MENTION_HERE_ID, MENTION_ID_ATTRIBUTE, MENTION_ITEM_TYPE_ATTRIBUTE, MENTION_LABEL_ATTRIBUTE, MENTION_SELECTOR, MENTION_TYPE, MENTION_TYPE_ATTRIBUTE, MIN_WINDOW_LOG, MentionType, NotFoundError, NotInitializedError, Operation, RoutePath, SITE_NAME, Serializable, UUIDV4_REGEX, WordFilteredError, applyItemMetadataMixin, capitalize, checkIsNestedInteraction, checkIsPlainObject, checkIsServer, chunk, chunkBySerializedSize, createItemEntityTypeSchema, createNormalizedStringSchema, createUniqueArraySchema, css, encodeUrlSubDelimiters, exhaustiveGuard, getDecodedUriComponent, getEndOfDay, getMentions, getOrCreate, getPropertyNames, getRawData, getResult, getResultAsync, getSynchronizedFunction, getWindowLog, getZonedDateTime, hrtime, html, jsonDateParse, mergeObjectsStrict, noop, normalizeString, now, sanitizeHtml, sanitizeTextHtml, settleAll, sleep, streamToText, takeOne, toAppError, toKebabCase, toRawDeep, truncate, uncapitalize, waitForSynchronizedFunctions, withFinalizer, withFinalizerAsync };
1918
+ export { ALL_SPECIAL_VALUES, CHARSET_PARAMETER_REGEX, CUSTOM_EMOJI_ID_ATTRIBUTE, CUSTOM_EMOJI_NAME_ATTRIBUTE, DEFAULT_ALLOWED_ATTRIBUTES, DEFAULT_ALLOWED_SCHEMES, DEFAULT_ALLOWED_TAGS, DEFAULT_COMPRESSION_LEVEL, DEFAULT_FACET_SCORE, DEFAULT_LINK_ATTRIBUTES, DEFAULT_SOURCE_SCORE, DEFAULT_TEXT_CHARSET, DEFAULT_TYPE_SCORE, ESCAPED_ATTRIBUTE_CHARACTERS_REGEX, ESCAPED_TEXT_CHARACTERS_REGEX, FacetScoreMap, ForbiddenError, GIBIBYTE, HTML_NAMESPACE, ID_SEPARATOR, IMPORTANT_REGEX, InvalidOperationError, ItemMetadata, KIBIBYTE, MAX_NESTING_DEPTH, MAX_READ_LIMIT, MAX_WINDOW_LOG, MEDIA_TYPE_REGEX, MENTION_EVERYONE_ID, MENTION_HERE_ID, MENTION_ID_ATTRIBUTE, MENTION_ITEM_TYPE_ATTRIBUTE, MENTION_LABEL_ATTRIBUTE, MENTION_SELECTOR, MENTION_TYPE, MENTION_TYPE_ATTRIBUTE, MIN_WINDOW_LOG, MentionType, NON_TEXT_TAGS, NotFoundError, NotInitializedError, ObjectMethod, Operation, PATH_SEPARATOR_REGEX, RoutePath, SANITIZER_ADVISORY_WATCH_SINCE, SITE_NAME, SPOILER_ATTRIBUTE, SPOILER_SELECTOR, SRCSET_ATTRIBUTE, SRCSET_DESCRIPTOR_REGEX, Serializable, SourceScoreMap, TEXT_MEDIA_TYPE_REGEX, TypeScoreMap, TypedEventEmitter, URL_ATTRIBUTES, UUIDV4_REGEX, VOID_TAGS, WordFilteredError, applyItemMetadataMixin, capitalize, charset, checkContainsProfanity, checkIsAllowedUrl, checkIsCustomMethod, checkIsDeepEqual, checkIsNestedInteraction, checkIsPlainObject, checkIsSameBytes, checkIsSameValueZero, checkIsServer, checkIsUnsafeUrlCharacter, checkIsWhitespaceCharacter, chunk, chunkBySerializedSize, collectText, contentType, createEvictingPromiseCache, createItemEntityTypeSchema, createNormalizedStringSchema, createUniqueArraySchema, css, dedent, encodeUrlSubDelimiters, englishProfaneWords, escapeAttribute, escapeCharacters, escapeText, exhaustiveGuard, extension, filterAttributes, filterClasses, filterHtml, filterSrcset, filterStyle, getChildNodes, getDecodedUriComponent, getEndOfDay, getEnumerableKeys, getExtensionMimeTypeMap, getMediaType, getMentions, getMimeScore, getMimeTypeEntryMap, getOrCreate, getPropertyNames, getRawData, getRequestError, getResult, getResultAsync, getSynchronizedFunction, getTransactionDone, getTransactionObjectStore, getWindowLog, getZonedDateTime, hrtime, html, jsonDateParse, lookup, matchesClassPattern, mergeObjectsStrict, noop, normalizeString, now, omitDeep, openDatabase, renderNode, reportFinalizerError, requestToPromise, sanitizeHtml, sanitizeTextHtml, settleAll, sleep, streamToText, takeOne, toAppError, toKebabCase, toRawDeep, truncate, uncapitalize, waitForSynchronizedFunctions, withFinalizer, withFinalizerAsync, wrapDatabase, wrapIndex, wrapObjectStore, wrapTransaction, wrapUpgradeDatabase, wrapUpgradeTransaction };