unhead 3.0.0 → 3.0.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.
- package/dist/client.d.mts +5 -5
- package/dist/client.d.ts +5 -5
- package/dist/client.mjs +2 -2
- package/dist/index.d.mts +54 -5
- package/dist/index.d.ts +54 -5
- package/dist/index.mjs +8 -1
- package/dist/parser.d.mts +1 -1
- package/dist/parser.d.ts +1 -1
- package/dist/plugins.d.mts +2 -2
- package/dist/plugins.d.ts +2 -2
- package/dist/scripts.d.mts +4 -4
- package/dist/scripts.d.ts +4 -4
- package/dist/server.d.mts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.mjs +3 -3
- package/dist/shared/{unhead.Dyr7L2Ht.d.mts → unhead.5pUZeb0i.d.mts} +154 -26
- package/dist/shared/{unhead.Dyr7L2Ht.d.ts → unhead.5pUZeb0i.d.ts} +154 -26
- package/dist/shared/{unhead.DbDvRsnF.d.mts → unhead.BAv4ddL5.d.mts} +1 -1
- package/dist/shared/{unhead.DmIUoNyg.d.ts → unhead.BEof8Qjb.d.ts} +1 -1
- package/dist/shared/{unhead.cnX_MFeG.d.ts → unhead.BRPfhzdc.d.ts} +2 -2
- package/dist/shared/{unhead.Db0zAB-x.d.mts → unhead.BxsOjg-Q.d.mts} +2 -2
- package/dist/shared/{unhead.Sr8_Iw6G.mjs → unhead.C5ypJnIO.mjs} +8 -4
- package/dist/shared/{unhead.BiaRAmcT.d.mts → unhead.CUEmFl2d.d.mts} +1 -1
- package/dist/shared/{unhead.D6A03PN3.d.mts → unhead.CyKsApKH.d.mts} +1 -1
- package/dist/shared/{unhead.DFKqTFly.d.ts → unhead.D_sLwV5L.d.ts} +2 -2
- package/dist/shared/{unhead.DQiBmCqH.mjs → unhead.DiRbsb3I.mjs} +9 -3
- package/dist/shared/{unhead.B825tVHL.d.mts → unhead.DvMT2vYs.d.mts} +2 -2
- package/dist/shared/{unhead.DvZZ4Zb_.d.ts → unhead.JGBJYEOZ.d.ts} +1 -1
- package/dist/shared/{unhead.DKz0V2If.d.ts → unhead.UFdAtJOd.d.ts} +1 -1
- package/dist/shared/{unhead.DyN7hSCT.d.mts → unhead.dhQT0IKI.d.mts} +1 -1
- package/dist/shared/{unhead.D4TxP3zZ.mjs → unhead.pv34ME7O.mjs} +1 -1
- package/dist/shared/{unhead.Cp3HtzBy.d.ts → unhead.vQPF0cJs.d.ts} +1 -1
- package/dist/stream/client.d.mts +3 -3
- package/dist/stream/client.d.ts +3 -3
- package/dist/stream/iife.global.js +1 -1
- package/dist/stream/iife.mjs +2 -2
- package/dist/stream/server.d.mts +3 -3
- package/dist/stream/server.d.ts +3 -3
- package/dist/stream/server.mjs +16 -3
- package/dist/types.d.mts +6 -6
- package/dist/types.d.ts +6 -6
- package/dist/utils.d.mts +2 -2
- package/dist/utils.d.ts +2 -2
- package/dist/utils.mjs +1 -1
- package/package.json +1 -1
|
@@ -878,20 +878,97 @@ interface PingbackLink extends LinkBase {
|
|
|
878
878
|
rel: 'pingback';
|
|
879
879
|
href: string;
|
|
880
880
|
}
|
|
881
|
+
/**
|
|
882
|
+
* Me link. Identifies the resource as representing the current user
|
|
883
|
+
* (IndieWeb / rel-me verification, Mastodon profile verification).
|
|
884
|
+
*
|
|
885
|
+
* @see https://html.spec.whatwg.org/multipage/links.html#link-type-me
|
|
886
|
+
*/
|
|
887
|
+
interface MeLink extends LinkBase {
|
|
888
|
+
rel: 'me';
|
|
889
|
+
href: string;
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Privacy policy link.
|
|
893
|
+
*
|
|
894
|
+
* @see https://html.spec.whatwg.org/multipage/links.html#link-type-privacy-policy
|
|
895
|
+
*/
|
|
896
|
+
interface PrivacyPolicyLink extends LinkBase {
|
|
897
|
+
rel: 'privacy-policy';
|
|
898
|
+
href: string;
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Terms of service link.
|
|
902
|
+
*
|
|
903
|
+
* @see https://html.spec.whatwg.org/multipage/links.html#link-type-terms-of-service
|
|
904
|
+
*/
|
|
905
|
+
interface TermsOfServiceLink extends LinkBase {
|
|
906
|
+
rel: 'terms-of-service';
|
|
907
|
+
href: string;
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Expect link. Blocks rendering until a named element is present and ready.
|
|
911
|
+
*
|
|
912
|
+
* @see https://html.spec.whatwg.org/multipage/links.html#link-type-expect
|
|
913
|
+
*/
|
|
914
|
+
interface ExpectLink extends LinkBase {
|
|
915
|
+
rel: 'expect';
|
|
916
|
+
href: string;
|
|
917
|
+
blocking?: 'render';
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Webmention endpoint link (IndieWeb).
|
|
921
|
+
*
|
|
922
|
+
* @see https://www.w3.org/TR/webmention/
|
|
923
|
+
*/
|
|
924
|
+
interface WebmentionLink extends LinkBase {
|
|
925
|
+
rel: 'webmention';
|
|
926
|
+
href: string;
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Compression dictionary link (experimental).
|
|
930
|
+
*
|
|
931
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/link#compression-dictionary
|
|
932
|
+
*/
|
|
933
|
+
interface CompressionDictionaryLink extends LinkBase {
|
|
934
|
+
rel: 'compression-dictionary';
|
|
935
|
+
href: string;
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Alternate stylesheet link. User-selectable alternate stylesheet.
|
|
939
|
+
* Requires a `title` to appear in the browser's stylesheet picker.
|
|
940
|
+
*
|
|
941
|
+
* @see https://html.spec.whatwg.org/multipage/semantics.html#rel-alternate-stylesheet
|
|
942
|
+
*/
|
|
943
|
+
interface AlternateStylesheetLink extends LinkBase, LinkHttpEvents {
|
|
944
|
+
rel: 'alternate stylesheet';
|
|
945
|
+
href: string;
|
|
946
|
+
title: string;
|
|
947
|
+
media?: string;
|
|
948
|
+
crossorigin?: '' | 'anonymous' | 'use-credentials';
|
|
949
|
+
integrity?: string;
|
|
950
|
+
type?: 'text/css' | (string & Record<never, never>);
|
|
951
|
+
disabled?: boolean;
|
|
952
|
+
}
|
|
881
953
|
/**
|
|
882
954
|
* Union of all `rel` values that have narrowed link type definitions.
|
|
883
955
|
* Useful for building type guards or conditional logic based on `rel` values.
|
|
884
956
|
*/
|
|
885
|
-
type KnownLinkRel = 'stylesheet' | 'preload' | 'modulepreload' | 'prefetch' | 'icon' | 'shortcut icon' | 'apple-touch-icon' | 'mask-icon' | 'manifest' | 'canonical' | 'dns-prefetch' | 'preconnect' | 'prerender' | 'alternate' | 'author' | 'license' | 'help' | 'search' | 'prev' | 'next' | 'pingback';
|
|
957
|
+
type KnownLinkRel = 'stylesheet' | 'alternate stylesheet' | 'preload' | 'modulepreload' | 'prefetch' | 'icon' | 'shortcut icon' | 'apple-touch-icon' | 'mask-icon' | 'manifest' | 'canonical' | 'dns-prefetch' | 'preconnect' | 'prerender' | 'alternate' | 'author' | 'license' | 'help' | 'search' | 'prev' | 'next' | 'pingback' | 'me' | 'webmention' | 'privacy-policy' | 'terms-of-service' | 'expect' | 'compression-dictionary';
|
|
886
958
|
/**
|
|
887
959
|
* Fallback for custom or unknown `rel` types.
|
|
888
960
|
*
|
|
889
|
-
* Not included in the {@link Link} union to prevent silent absorption of known
|
|
890
|
-
*
|
|
961
|
+
* Not included in the {@link Link} union to prevent silent absorption of known
|
|
962
|
+
* `rel` values (e.g. so `rel: 'preload'` without `as` stays an error instead of
|
|
963
|
+
* collapsing into this permissive shape).
|
|
964
|
+
*
|
|
965
|
+
* For non-standard `rel` values not covered by {@link KnownLinkRel}, prefer
|
|
966
|
+
* {@link defineLink}, which enforces strict narrowing on known rels while
|
|
967
|
+
* accepting `GenericLink` for anything else:
|
|
891
968
|
*
|
|
892
969
|
* ```ts
|
|
893
|
-
* import
|
|
894
|
-
* useHead({ link: [{ rel: '
|
|
970
|
+
* import { defineLink } from 'unhead'
|
|
971
|
+
* useHead({ link: [defineLink({ rel: 'openid2.provider', href: 'https://...' })] })
|
|
895
972
|
* ```
|
|
896
973
|
*/
|
|
897
974
|
interface GenericLink extends LinkBase {
|
|
@@ -918,15 +995,33 @@ interface GenericLink extends LinkBase {
|
|
|
918
995
|
* attributes. For example, `rel="preload"` requires the `as` attribute (see {@link PreloadLink}),
|
|
919
996
|
* and `rel="mask-icon"` requires `color` (see {@link MaskIconLink}).
|
|
920
997
|
*
|
|
921
|
-
* For
|
|
998
|
+
* For non-standard `rel` values not covered by {@link KnownLinkRel}, use {@link defineLink}:
|
|
922
999
|
* ```ts
|
|
923
|
-
* import
|
|
924
|
-
* useHead({ link: [{ rel: '
|
|
1000
|
+
* import { defineLink } from 'unhead'
|
|
1001
|
+
* useHead({ link: [defineLink({ rel: 'openid2.provider', href: 'https://...' })] })
|
|
925
1002
|
* ```
|
|
926
1003
|
*
|
|
927
1004
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel
|
|
928
1005
|
*/
|
|
929
|
-
type Link = StylesheetLink | PreloadLink | ModulepreloadLink | PrefetchLink | FaviconLink | AppleTouchIconLink | MaskIconLink | ManifestLink | CanonicalLink | DnsPrefetchLink | PreconnectLink | PrerenderLink | AlternateLanguageLink | AlternateFeedLink | AlternateMediaLink | BareAlternateLink | AuthorLink | LicenseLink | HelpLink | SearchLink | PrevLink | NextLink | PingbackLink;
|
|
1006
|
+
type Link = StylesheetLink | AlternateStylesheetLink | PreloadLink | ModulepreloadLink | PrefetchLink | FaviconLink | AppleTouchIconLink | MaskIconLink | ManifestLink | CanonicalLink | DnsPrefetchLink | PreconnectLink | PrerenderLink | AlternateLanguageLink | AlternateFeedLink | AlternateMediaLink | BareAlternateLink | AuthorLink | LicenseLink | HelpLink | SearchLink | PrevLink | NextLink | PingbackLink | MeLink | WebmentionLink | PrivacyPolicyLink | TermsOfServiceLink | ExpectLink | CompressionDictionaryLink;
|
|
1007
|
+
/**
|
|
1008
|
+
* Pick {@link Link} union members whose `rel` accepts `R`.
|
|
1009
|
+
*
|
|
1010
|
+
* Unlike `Extract<Link, { rel: R }>`, this handles members whose `rel` is itself
|
|
1011
|
+
* a union (e.g. {@link FaviconLink}'s `'icon' | 'shortcut icon'`).
|
|
1012
|
+
*/
|
|
1013
|
+
type MatchLinkByRel<R> = Link extends infer M ? M extends {
|
|
1014
|
+
rel: infer MR;
|
|
1015
|
+
} ? R extends MR ? M : never : never : never;
|
|
1016
|
+
/**
|
|
1017
|
+
* Resolve a single link input to either its strict {@link Link} variant (when
|
|
1018
|
+
* `rel` is a {@link KnownLinkRel}) or {@link GenericLink} (for custom rels).
|
|
1019
|
+
*/
|
|
1020
|
+
type InferLink<T> = T extends {
|
|
1021
|
+
rel: infer R;
|
|
1022
|
+
} ? R extends KnownLinkRel ? MatchLinkByRel<R> : R extends string ? GenericLink & {
|
|
1023
|
+
rel: R;
|
|
1024
|
+
} : never : never;
|
|
930
1025
|
|
|
931
1026
|
/**
|
|
932
1027
|
* Known meta name values
|
|
@@ -2109,14 +2204,16 @@ interface NoLoadableScriptProps {
|
|
|
2109
2204
|
nomodule?: never;
|
|
2110
2205
|
}
|
|
2111
2206
|
/**
|
|
2112
|
-
* Content for data scripts
|
|
2207
|
+
* Content for data scripts — requires exactly one of `textContent` or
|
|
2208
|
+
* `innerHTML`. Data scripts (JSON-LD, speculation rules, application/json) must
|
|
2209
|
+
* carry inline content; an empty payload is invalid.
|
|
2113
2210
|
*/
|
|
2114
2211
|
type DataScriptTextContent<T = string | Record<string, unknown>> = {
|
|
2115
2212
|
/**
|
|
2116
2213
|
* Sets the textContent of an element. Safer for XSS.
|
|
2117
2214
|
* Can be a string or an object that will be serialized to JSON.
|
|
2118
2215
|
*/
|
|
2119
|
-
textContent
|
|
2216
|
+
textContent: T;
|
|
2120
2217
|
innerHTML?: never;
|
|
2121
2218
|
} | {
|
|
2122
2219
|
textContent?: never;
|
|
@@ -2124,7 +2221,7 @@ type DataScriptTextContent<T = string | Record<string, unknown>> = {
|
|
|
2124
2221
|
* Sets the innerHTML of an element.
|
|
2125
2222
|
* Can be a string or an object that will be serialized to JSON.
|
|
2126
2223
|
*/
|
|
2127
|
-
innerHTML
|
|
2224
|
+
innerHTML: T;
|
|
2128
2225
|
};
|
|
2129
2226
|
/**
|
|
2130
2227
|
* External JavaScript (fires events)
|
|
@@ -2307,7 +2404,7 @@ interface ImportMapConfig {
|
|
|
2307
2404
|
scopes?: Record<string, Record<string, string>>;
|
|
2308
2405
|
}
|
|
2309
2406
|
/**
|
|
2310
|
-
* Import map
|
|
2407
|
+
* Import map. Requires either `textContent` (recommended) or `innerHTML`.
|
|
2311
2408
|
*/
|
|
2312
2409
|
type ImportMapScript = ScriptBase & NoLoadableScriptProps & {
|
|
2313
2410
|
/**
|
|
@@ -2317,13 +2414,15 @@ type ImportMapScript = ScriptBase & NoLoadableScriptProps & {
|
|
|
2317
2414
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
|
|
2318
2415
|
*/
|
|
2319
2416
|
type: 'importmap';
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
* Can be a string or an ImportMapConfig object that will be serialized to JSON.
|
|
2323
|
-
*/
|
|
2417
|
+
} & ({
|
|
2418
|
+
/** Import map content as a string or ImportMapConfig object (auto-serialized). */
|
|
2324
2419
|
textContent: string | ImportMapConfig;
|
|
2325
2420
|
innerHTML?: never;
|
|
2326
|
-
}
|
|
2421
|
+
} | {
|
|
2422
|
+
textContent?: never;
|
|
2423
|
+
/** Import map content as a string or ImportMapConfig object (auto-serialized). */
|
|
2424
|
+
innerHTML: string | ImportMapConfig;
|
|
2425
|
+
});
|
|
2327
2426
|
/**
|
|
2328
2427
|
* Application JSON script (generic JSON data)
|
|
2329
2428
|
*/
|
|
@@ -2339,12 +2438,16 @@ type ApplicationJsonScript = ScriptBase & NoLoadableScriptProps & DataScriptText
|
|
|
2339
2438
|
/**
|
|
2340
2439
|
* Fallback for custom or unknown `type` values.
|
|
2341
2440
|
*
|
|
2342
|
-
* Not included in the {@link Script} union to prevent silent absorption of known
|
|
2343
|
-
*
|
|
2441
|
+
* Not included in the {@link Script} union to prevent silent absorption of known
|
|
2442
|
+
* `type` values (e.g. so `type: 'module'` without `src` or inline content stays
|
|
2443
|
+
* an error instead of collapsing into this permissive shape).
|
|
2444
|
+
*
|
|
2445
|
+
* For custom `type` values, prefer {@link defineScript}, which enforces strict
|
|
2446
|
+
* narrowing on known types while accepting `GenericScript` for anything else:
|
|
2344
2447
|
*
|
|
2345
2448
|
* ```ts
|
|
2346
|
-
* import
|
|
2347
|
-
* useHead({ script: [{ type: 'text/plain', textContent: '...' }
|
|
2449
|
+
* import { defineScript } from 'unhead'
|
|
2450
|
+
* useHead({ script: [defineScript({ type: 'text/plain', textContent: '...' })] })
|
|
2348
2451
|
* ```
|
|
2349
2452
|
*/
|
|
2350
2453
|
interface GenericScript extends ScriptBase, ScriptHttpEvents {
|
|
@@ -2420,13 +2523,38 @@ interface GenericScript extends ScriptBase, ScriptHttpEvents {
|
|
|
2420
2523
|
* Each `type` value maps to a specific interface that enforces per-type constraints.
|
|
2421
2524
|
* For example, inline scripts require `textContent` and forbid `src`/`async`/`defer`.
|
|
2422
2525
|
*
|
|
2423
|
-
* For custom or non-standard `type` values, use {@link
|
|
2526
|
+
* For custom or non-standard `type` values, use {@link defineScript}:
|
|
2424
2527
|
* ```ts
|
|
2425
|
-
* import
|
|
2426
|
-
* useHead({ script: [{ type: 'text/plain', textContent: '...' }
|
|
2528
|
+
* import { defineScript } from 'unhead'
|
|
2529
|
+
* useHead({ script: [defineScript({ type: 'text/plain', textContent: '...' })] })
|
|
2427
2530
|
* ```
|
|
2428
2531
|
*/
|
|
2429
2532
|
type Script = ExternalScript | ModuleScript | InlineScript | InlineModuleScript | JsonLdScript | SpeculationRulesScript | ImportMapScript | ApplicationJsonScript;
|
|
2533
|
+
/**
|
|
2534
|
+
* Union of all `type` values that have narrowed script type definitions.
|
|
2535
|
+
*/
|
|
2536
|
+
type KnownScriptType = '' | 'text/javascript' | 'module' | 'application/ld+json' | 'speculationrules' | 'importmap' | 'application/json';
|
|
2537
|
+
/**
|
|
2538
|
+
* Pick {@link Script} union members whose `type` accepts `U`.
|
|
2539
|
+
*
|
|
2540
|
+
* Handles members whose `type` is itself a union (e.g. {@link ExternalScript}'s
|
|
2541
|
+
* `'' | 'text/javascript'`), and members where `type` is optional.
|
|
2542
|
+
*/
|
|
2543
|
+
type MatchScriptByType<U> = Script extends infer M ? M extends {
|
|
2544
|
+
type?: infer MT;
|
|
2545
|
+
} ? U extends MT ? M : never : never : never;
|
|
2546
|
+
/**
|
|
2547
|
+
* Resolve a single script input to either its strict {@link Script} variant (when
|
|
2548
|
+
* `type` is a {@link KnownScriptType}) or {@link GenericScript} (for custom types).
|
|
2549
|
+
*
|
|
2550
|
+
* When no `type` field is present, or `type` is non-string, the full {@link Script}
|
|
2551
|
+
* union is returned so discriminators like `src` vs `textContent` still apply.
|
|
2552
|
+
*/
|
|
2553
|
+
type InferScript<T> = T extends {
|
|
2554
|
+
type: infer U;
|
|
2555
|
+
} ? U extends string ? U extends KnownScriptType ? MatchScriptByType<U> : GenericScript & {
|
|
2556
|
+
type: U;
|
|
2557
|
+
} : Script : Script;
|
|
2430
2558
|
|
|
2431
2559
|
interface Style extends Pick<GlobalAttributes, 'nonce' | 'id'>, Blocking {
|
|
2432
2560
|
/**
|
|
@@ -2745,4 +2873,4 @@ interface HeadTag extends TagPriority, TagPosition, ResolvesDuplicates, HasTempl
|
|
|
2745
2873
|
}
|
|
2746
2874
|
type HeadTagKeys = (keyof HeadTag)[];
|
|
2747
2875
|
|
|
2748
|
-
export type {
|
|
2876
|
+
export type { Meta as $, AlternateFeedLink as A, Booleanable as B, CanonicalLink as C, DataKeys as D, ExpectLink as E, FaviconLink as F, GenericLink as G, HasTemplateParams as H, IconLink as I, InferScript as J, InlineModuleScript as K, InlineScript as L, InnerContent as M, InnerContentVal as N, InternalTagKey as O, JsonLdScript as P, KnownLinkRel as Q, KnownScriptType as R, LicenseLink as S, Link as T, LinkBase as U, LinkHttpEvents as V, ManifestLink as W, MaskIconLink as X, MaybeArray as Y, MaybeEventFnHandlers as Z, MeLink as _, AlternateLanguageLink as a, UseHeadInput as a$, MetaBase as a0, MetaFlat as a1, MetaGeneric as a2, MetaNames as a3, MetaProperties as a4, ModuleScript as a5, ModulepreloadLink as a6, NameMeta as a7, Never as a8, NextLink as a9, ResolvableTemplateParams as aA, ResolvableTitle as aB, ResolvableTitleTemplate as aC, ResolvableUnion as aD, ResolvableValue as aE, ResolvesDuplicates as aF, SchemaAugmentations as aG, Script as aH, ScriptBase as aI, ScriptHttpEvents as aJ, SearchLink as aK, SerializableHead as aL, SpeculationRules as aM, SpeculationRulesScript as aN, StringInnerContent as aO, Stringable as aP, StylesheetLink as aQ, TagKey as aR, TagPosition as aS, TagPriority as aT, TagUserProperties as aU, TemplateParams as aV, TemplateParamsAugmentations as aW, TermsOfServiceLink as aX, UnheadBodyAttributesWithoutEvents as aY, UnheadHtmlAttributes as aZ, UnheadMeta as a_, PingbackLink as aa, PreconnectLink as ab, PrefetchLink as ac, PreloadFontLink as ad, PreloadImageLink as ae, PreloadLink as af, PreloadLinkBase as ag, PreloadOtherLink as ah, PreloadScriptLink as ai, PreloadStyleLink as aj, PrerenderLink as ak, PrevLink as al, PrivacyPolicyLink as am, ProcessesTemplateParams as an, PropertyMeta as ao, RawInput as ap, ResolvableBase as aq, ResolvableBodyAttributes as ar, ResolvableHead as as, ResolvableHtmlAttributes as at, ResolvableLink as au, ResolvableMeta as av, ResolvableNoscript as aw, ResolvableProperties as ax, ResolvableScript as ay, ResolvableStyle as az, AlternateLink as b, UseSeoMetaInput as b0, ValidTagPositions as b1, WebmentionLink as b2, AlternateMediaLink as c, AlternateStylesheetLink as d, AppleTouchIconLink as e, ApplicationJsonScript as f, Arrayable as g, AuthorLink as h, BareAlternateLink as i, BodyAttributesWithoutEvents as j, BodyEvents as k, CharsetMeta as l, CompressionDictionaryLink as m, DeepResolvableProperties as n, DnsPrefetchLink as o, ExternalScript as p, GenericScript as q, GlobalAttributes as r, HeadTag as s, HeadTagKeys as t, HelpLink as u, HttpEquivMeta as v, HttpEventAttributes as w, ImportMapConfig as x, ImportMapScript as y, InferLink as z };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HookableCore } from 'hookable';
|
|
2
|
-
import {
|
|
2
|
+
import { q as GenericScript, aJ as ScriptHttpEvents, D as DataKeys, Z as MaybeEventFnHandlers, w as HttpEventAttributes, aG as SchemaAugmentations, s as HeadTag, as as ResolvableHead, aS as TagPosition, aT as TagPriority, an as ProcessesTemplateParams, aF as ResolvesDuplicates, aV as TemplateParams } from './unhead.5pUZeb0i.js';
|
|
3
3
|
|
|
4
4
|
type UseScriptStatus = 'awaitingLoad' | 'loading' | 'loaded' | 'error' | 'removed';
|
|
5
5
|
type UseScriptContext<T extends Record<symbol | string, any>> = ScriptInstance<T>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HookableCore } from 'hookable';
|
|
2
|
-
import { U as Unhead, s as SSRHeadPayload, v as ServerHeadHooks, e as CreateServerHeadOptions } from './unhead.
|
|
3
|
-
import {
|
|
2
|
+
import { U as Unhead, s as SSRHeadPayload, v as ServerHeadHooks, e as CreateServerHeadOptions } from './unhead.BEof8Qjb.js';
|
|
3
|
+
import { as as ResolvableHead } from './unhead.5pUZeb0i.js';
|
|
4
4
|
|
|
5
5
|
interface ServerUnhead<T = ResolvableHead> extends Unhead<T, SSRHeadPayload> {
|
|
6
6
|
hooks: HookableCore<ServerHeadHooks>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HookableCore } from 'hookable';
|
|
2
|
-
import { U as Unhead, C as ClientHeadHooks, c as CreateClientHeadOptions } from './unhead.
|
|
3
|
-
import {
|
|
2
|
+
import { U as Unhead, C as ClientHeadHooks, c as CreateClientHeadOptions } from './unhead.CyKsApKH.mjs';
|
|
3
|
+
import { as as ResolvableHead } from './unhead.5pUZeb0i.mjs';
|
|
4
4
|
|
|
5
5
|
interface ClientUnhead<T = ResolvableHead> extends Unhead<T, boolean> {
|
|
6
6
|
hooks: HookableCore<ClientHeadHooks>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { c as createUnhead, r as registerPlugin } from './unhead.CfgPMHXt.mjs';
|
|
2
2
|
import { a as callHook, c as createHooks } from './unhead.DvIxXxuO.mjs';
|
|
3
|
-
import { r as resolveTags } from './unhead.
|
|
3
|
+
import { r as resolveTags } from './unhead.DiRbsb3I.mjs';
|
|
4
4
|
import { b as TagPriorityAliases, c as TagsWithInnerContent, a as SelfClosingTags } from './unhead.fg-0ge_u.mjs';
|
|
5
5
|
|
|
6
6
|
const TAG_WEIGHTS = { base: -10, title: 10 };
|
|
7
7
|
const CAPO_WEIGHTS = {
|
|
8
8
|
meta: { "content-security-policy": -30, "charset": -20, "viewport": -15 },
|
|
9
9
|
link: { "preconnect": 20, "stylesheet": 60, "preload": 70, "modulepreload": 70, "prefetch": 90, "dns-prefetch": 90, "prerender": 90 },
|
|
10
|
-
script: { async: 30, defer: 80, sync: 50 },
|
|
10
|
+
script: { importmap: 25, async: 30, defer: 80, sync: 50, speculationrules: 90 },
|
|
11
11
|
style: { imported: 40, sync: 60 }
|
|
12
12
|
};
|
|
13
13
|
const ImportStyleRe = /@import/;
|
|
@@ -27,9 +27,13 @@ function capoTagWeight(tag) {
|
|
|
27
27
|
weight = CAPO_WEIGHTS.link[tag.props.rel];
|
|
28
28
|
} else if (tag.tag === "script") {
|
|
29
29
|
const type = String(tag.props.type);
|
|
30
|
-
if (
|
|
30
|
+
if (type === "importmap")
|
|
31
|
+
weight = CAPO_WEIGHTS.script.importmap;
|
|
32
|
+
else if (type === "speculationrules")
|
|
33
|
+
weight = CAPO_WEIGHTS.script.speculationrules;
|
|
34
|
+
else if (isTruthy(tag.props.async))
|
|
31
35
|
weight = CAPO_WEIGHTS.script.async;
|
|
32
|
-
else if (tag.props.src && !isTruthy(tag.props.defer) && !isTruthy(tag.props.async) && type !== "module" && !type.endsWith("json") || tag.innerHTML && !type.endsWith("json"))
|
|
36
|
+
else if (tag.props.src && !isTruthy(tag.props.defer) && !isTruthy(tag.props.async) && type !== "module" && !type.endsWith("json") || (tag.innerHTML || tag.textContent) && !type.endsWith("json"))
|
|
33
37
|
weight = CAPO_WEIGHTS.script.sync;
|
|
34
38
|
else if (isTruthy(tag.props.defer) && tag.props.src && !isTruthy(tag.props.async) || type === "module")
|
|
35
39
|
weight = CAPO_WEIGHTS.script.defer;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ap as RawInput, as as ResolvableHead, aE as ResolvableValue, ax as ResolvableProperties, G as GenericLink, D as DataKeys, aG as SchemaAugmentations, a2 as MetaGeneric, q as GenericScript, aZ as UnheadHtmlAttributes, aY as UnheadBodyAttributesWithoutEvents } from './unhead.5pUZeb0i.mjs';
|
|
2
2
|
|
|
3
3
|
type Base = RawInput<'base'>;
|
|
4
4
|
type HtmlAttributes = RawInput<'htmlAttrs'>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HookableCore } from 'hookable';
|
|
2
|
-
import {
|
|
2
|
+
import { q as GenericScript, aJ as ScriptHttpEvents, D as DataKeys, Z as MaybeEventFnHandlers, w as HttpEventAttributes, aG as SchemaAugmentations, s as HeadTag, as as ResolvableHead, aS as TagPosition, aT as TagPriority, an as ProcessesTemplateParams, aF as ResolvesDuplicates, aV as TemplateParams } from './unhead.5pUZeb0i.mjs';
|
|
3
3
|
|
|
4
4
|
type UseScriptStatus = 'awaitingLoad' | 'loading' | 'loaded' | 'error' | 'removed';
|
|
5
5
|
type UseScriptContext<T extends Record<symbol | string, any>> = ScriptInstance<T>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HookableCore } from 'hookable';
|
|
2
|
-
import { U as Unhead, C as ClientHeadHooks, c as CreateClientHeadOptions } from './unhead.
|
|
3
|
-
import {
|
|
2
|
+
import { U as Unhead, C as ClientHeadHooks, c as CreateClientHeadOptions } from './unhead.BEof8Qjb.js';
|
|
3
|
+
import { as as ResolvableHead } from './unhead.5pUZeb0i.js';
|
|
4
4
|
|
|
5
5
|
interface ClientUnhead<T = ResolvableHead> extends Unhead<T, boolean> {
|
|
6
6
|
hooks: HookableCore<ClientHeadHooks>;
|
|
@@ -102,7 +102,7 @@ function normalizeProps(tag, input) {
|
|
|
102
102
|
} else if (TagConfigKeys.has(prop)) {
|
|
103
103
|
if ((prop === "textContent" || prop === "innerHTML") && typeof value === "object") {
|
|
104
104
|
const type = input.type || "application/json";
|
|
105
|
-
if (type.endsWith("json") || type === "speculationrules") {
|
|
105
|
+
if (type.endsWith("json") || type === "speculationrules" || type === "importmap") {
|
|
106
106
|
tag.props.type = input.type = type;
|
|
107
107
|
tag[prop] = JSON.stringify(value);
|
|
108
108
|
}
|
|
@@ -205,8 +205,14 @@ function sanitizeTags(tags) {
|
|
|
205
205
|
return false;
|
|
206
206
|
if (tag === "meta" && !props.content && !props["http-equiv"] && !props.charset)
|
|
207
207
|
return false;
|
|
208
|
-
if (tag === "script" && innerHTML) {
|
|
209
|
-
|
|
208
|
+
if (tag === "script" && (innerHTML || t.textContent)) {
|
|
209
|
+
const type = String(props.type);
|
|
210
|
+
const isJsonLike = type.endsWith("json") || type === "importmap" || type === "speculationrules";
|
|
211
|
+
const escape = (content) => isJsonLike ? (typeof content === "string" ? content : JSON.stringify(content)).replace(LT_RE, "\\u003C") : typeof content === "string" ? content.replace(SCRIPT_END_RE, "<\\/script") : content;
|
|
212
|
+
if (innerHTML)
|
|
213
|
+
t.innerHTML = escape(innerHTML);
|
|
214
|
+
if (t.textContent)
|
|
215
|
+
t.textContent = escape(t.textContent);
|
|
210
216
|
t._d = dedupeKey(t);
|
|
211
217
|
}
|
|
212
218
|
return true;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HookableCore } from 'hookable';
|
|
2
|
-
import { U as Unhead, s as SSRHeadPayload, v as ServerHeadHooks, e as CreateServerHeadOptions } from './unhead.
|
|
3
|
-
import {
|
|
2
|
+
import { U as Unhead, s as SSRHeadPayload, v as ServerHeadHooks, e as CreateServerHeadOptions } from './unhead.CyKsApKH.mjs';
|
|
3
|
+
import { as as ResolvableHead } from './unhead.5pUZeb0i.mjs';
|
|
4
4
|
|
|
5
5
|
interface ServerUnhead<T = ResolvableHead> extends Unhead<T, SSRHeadPayload> {
|
|
6
6
|
hooks: HookableCore<ServerHeadHooks>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ap as RawInput, as as ResolvableHead, aE as ResolvableValue, ax as ResolvableProperties, G as GenericLink, D as DataKeys, aG as SchemaAugmentations, a2 as MetaGeneric, q as GenericScript, aZ as UnheadHtmlAttributes, aY as UnheadBodyAttributesWithoutEvents } from './unhead.5pUZeb0i.js';
|
|
2
2
|
|
|
3
3
|
type Base = RawInput<'base'>;
|
|
4
4
|
type HtmlAttributes = RawInput<'htmlAttrs'>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { U as Unhead, F as UseScriptInput, G as UseScriptOptions, J as UseScriptReturn } from './unhead.
|
|
1
|
+
import { U as Unhead, F as UseScriptInput, G as UseScriptOptions, J as UseScriptReturn } from './unhead.CyKsApKH.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Load third-party scripts with SSR support and a proxied API.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { H as HasElementTags } from './unhead.fg-0ge_u.mjs';
|
|
2
|
-
import { b as normalizeProps, d as dedupeKey, h as hashTag, r as resolveTags, i as isMetaArrayDupeKey } from './unhead.
|
|
2
|
+
import { b as normalizeProps, d as dedupeKey, h as hashTag, r as resolveTags, i as isMetaArrayDupeKey } from './unhead.DiRbsb3I.mjs';
|
|
3
3
|
import { a as callHook } from './unhead.DvIxXxuO.mjs';
|
|
4
4
|
|
|
5
5
|
const WHITESPACE_RE = /\s+/;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { U as Unhead, F as UseScriptInput, G as UseScriptOptions, J as UseScriptReturn } from './unhead.
|
|
1
|
+
import { U as Unhead, F as UseScriptInput, G as UseScriptOptions, J as UseScriptReturn } from './unhead.BEof8Qjb.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Load third-party scripts with SSR support and a proxied API.
|
package/dist/stream/client.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as ClientUnhead } from '../shared/unhead.
|
|
2
|
-
import { c as CreateClientHeadOptions, U as Unhead } from '../shared/unhead.
|
|
3
|
-
import {
|
|
1
|
+
import { C as ClientUnhead } from '../shared/unhead.BxsOjg-Q.mjs';
|
|
2
|
+
import { c as CreateClientHeadOptions, U as Unhead } from '../shared/unhead.CyKsApKH.mjs';
|
|
3
|
+
import { aL as SerializableHead, as as ResolvableHead } from '../shared/unhead.5pUZeb0i.mjs';
|
|
4
4
|
import 'hookable';
|
|
5
5
|
|
|
6
6
|
interface UnheadStreamQueue {
|
package/dist/stream/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as ClientUnhead } from '../shared/unhead.
|
|
2
|
-
import { c as CreateClientHeadOptions, U as Unhead } from '../shared/unhead.
|
|
3
|
-
import {
|
|
1
|
+
import { C as ClientUnhead } from '../shared/unhead.D_sLwV5L.js';
|
|
2
|
+
import { c as CreateClientHeadOptions, U as Unhead } from '../shared/unhead.BEof8Qjb.js';
|
|
3
|
+
import { aL as SerializableHead, as as ResolvableHead } from '../shared/unhead.5pUZeb0i.js';
|
|
4
4
|
import 'hookable';
|
|
5
5
|
|
|
6
6
|
interface UnheadStreamQueue {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var __unhead_iife__ = (function (exports) { 'use strict'; const DupeableTags = new Set(["link", "style", "script", "noscript"]); const TagsWithInnerContent = new Set(["title", "titleTemplate", "script", "style", "noscript"]); const HasElementTags = new Set(["base", "meta", "link", "style", "script", "noscript"]); const ValidHeadTags = new Set(["title", "base", "htmlAttrs", "bodyAttrs", "meta", "link", "style", "script", "noscript"]); const UniqueTags = new Set(["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs", "templateParams"]); const TagConfigKeys = new Set(["key", "tagPosition", "tagPriority", "tagDuplicateStrategy", "innerHTML", "textContent", "processTemplateParams"]); const UsesMergeStrategy = new Set(["templateParams", "htmlAttrs", "bodyAttrs"]); const MetaTagsArrayable = new Set([ "theme-color", "google-site-verification", "og", "article", "book", "profile", "twitter", "author" ]); function callHook(head, hook, ctx) { return head.hooks?.callHook(hook, ctx); } const META_NOREWRITE_RE = /^(?:viewport|description|keywords|robots)$/; function isMetaArrayDupeKey(v) { return MetaTagsArrayable.has(v.split(":")[1]); } function dedupeKey(tag) { const { props, tag: t, key } = tag; if (UniqueTags.has(t)) return t; if (t === "link" && props.rel === "canonical") return "canonical"; if (t === "link" && props.rel === "alternate") { const altKey = props.hreflang || props.type; if (altKey) return `alternate:${altKey}`; } if (props.charset) return "charset"; if (t === "meta") { for (const n of ["name", "property", "http-equiv"]) { const v = props[n]; if (v !== void 0) return `meta:${v}${(typeof v !== "string" || !v.includes(":")) && !META_NOREWRITE_RE.test(v) && key ? `:key:${key}` : ""}`; } } if (key) return `${t}:key:${key}`; if (props.id) return `${t}:id:${props.id}`; if (t === "link" && props.rel === "alternate") return `alternate:${props.href || ""}`; return TagsWithInnerContent.has(t) && (tag.textContent || tag.innerHTML) ? `${t}:content:${tag.textContent || tag.innerHTML}` : void 0; } function hashTag(tag) { return tag._h || tag._d || tag.textContent || tag.innerHTML || `${tag.tag}:${Object.entries(tag.props).map(([k, v]) => `${k}:${String(v)}`).join()}`; } function walkResolver(val, resolve, key) { if (key === "_resolver") return val; if (typeof val === "function" && (!key || key !== "titleTemplate" && !key.startsWith("on"))) val = val(); const v = resolve ? resolve(key, val) : val; if (Array.isArray(v)) return v.map((r) => walkResolver(r, resolve)); if (v?.constructor === Object) { const next = {}; for (const k in v) { if (k === "__proto__" || k === "constructor" || k === "prototype") continue; next[k] = walkResolver(v[k], resolve, k); } return next; } return v; } function normalizeStyleClassProps(key, value) { const isStyle = key === "style"; const store = isStyle ? new Map() : new Set(); const add = (v) => { if (!v) return; if (isStyle) { const i = v.indexOf(":"); i > 0 && store.set(v.slice(0, i).trim(), v.slice(i + 1).trim()); } else { v.split(" ").forEach((c) => c && store.add(c)); } }; if (typeof value === "string") { (isStyle ? value.split(";") : [value]).forEach(add); } else if (Array.isArray(value)) { value.forEach(add); } else if (value && typeof value === "object") { for (const k in value) { const v = value[k]; v && v !== "false" && (isStyle ? store.set(k.trim(), String(v)) : add(k)); } } return store; } function normalizeProps(tag, input) { tag.props = tag.props || {}; if (!input) return tag; if (tag.tag === "templateParams") { tag.props = input; return tag; } const isHtmlTag = HasElementTags.has(tag.tag) || tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs"; for (const prop in input) { if (prop === "__proto__" || prop === "constructor" || prop === "prototype") continue; const value = input[prop]; if (value === null) { tag.props[prop] = null; } else if (prop === "class" || prop === "style") { tag.props[prop] = normalizeStyleClassProps(prop, value); } else if (TagConfigKeys.has(prop)) { if ((prop === "textContent" || prop === "innerHTML") && typeof value === "object") { const type = input.type || "application/json"; if (type.endsWith("json") || type === "speculationrules") { tag.props.type = input.type = type; tag[prop] = JSON.stringify(value); } } else { tag[prop] = value; } } else if (value !== void 0) { const isData = prop.startsWith("data-"); const key = isHtmlTag && !isData ? prop.toLowerCase() : prop; const str = String(value); const isMeta = tag.tag === "meta" && key === "content"; tag.props[key] = str === "true" || str === "" ? isData || isMeta ? str : true : !value && isData && str === "false" ? "false" : value; } } return tag; } function normalizeTag(tagName, _input) { const input = typeof _input === "object" && typeof _input !== "function" ? _input : { [tagName === "script" || tagName === "noscript" || tagName === "style" ? "innerHTML" : "textContent"]: _input }; const tag = normalizeProps({ tag: tagName, props: {} }, input); if (tag.key && DupeableTags.has(tag.tag)) tag.props["data-hid"] = tag._h = tag.key; if (tag.tag === "script" && typeof tag.innerHTML === "object") { tag.innerHTML = JSON.stringify(tag.innerHTML); tag.props.type = tag.props.type || "application/json"; } return Array.isArray(tag.props.content) ? tag.props.content.map((v) => ({ ...tag, props: { ...tag.props, content: v } })) : tag; } function normalizeEntryToTags(input, propResolvers) { if (!input) return []; if (typeof input === "function") input = input(); const resolvers = (key, val) => { for (const r of propResolvers) val = r(key, val); return val; }; input = walkResolver(resolvers(void 0, input), resolvers); const tags = []; for (const key in input) { const value = input[key]; if (value !== void 0) { for (const v of Array.isArray(value) ? value : [value]) tags.push(normalizeTag(key, v)); } } return tags.flat(); } const LT_RE = /</g; const SCRIPT_END_RE = /<\/script/g; const sortTags = (a, b) => a._w === b._w ? a._p - b._p : a._w - b._w; function dedupeTags(ctx) { let hasFlatMeta = false; for (const next of ctx.tags.sort(sortTags)) { const k = next._d || hashTag(next); const prev = ctx.tagMap.get(k); if (!prev) { ctx.tagMap.set(k, next); continue; } const strategy = next.tagDuplicateStrategy || (UsesMergeStrategy.has(next.tag) ? "merge" : null) || (next.key && next.key === prev.key ? "merge" : null); if (strategy === "merge") { const props = { ...prev.props }; for (const p in next.props) { props[p] = p === "style" ? new Map([...prev.props.style || new Map(), ...next.props[p]]) : p === "class" ? new Set([...prev.props.class || [], ...next.props[p]]) : next.props[p]; } ctx.tagMap.set(k, { ...next, props }); } else if (next._p >> 10 === prev._p >> 10 && next.tag === "meta" && isMetaArrayDupeKey(k)) { ctx.tagMap.set(k, Object.assign([...Array.isArray(prev) ? prev : [prev], next], next)); hasFlatMeta = true; } else if (next._w === prev._w ? next._p > prev._p : next._w < prev._w) { ctx.tagMap.set(k, next); } } return hasFlatMeta; } function resolveTitleTemplate(ctx, head) { const title = ctx.tagMap.get("title"); const tpl = ctx.tagMap.get("titleTemplate"); head._title = title?.textContent; if (!tpl) return; const fn = tpl.textContent; head._titleTemplate = fn; if (!fn) return; let v = typeof fn === "function" ? fn(title?.textContent) : fn; if (typeof v === "string" && !head.plugins.has("template-params")) v = v.replace("%s", title?.textContent || ""); if (title) { v === null ? ctx.tagMap.delete("title") : ctx.tagMap.set("title", { ...title, textContent: v }); } else { ctx.tagMap.set("titleTemplate", { ...tpl, tag: "title", textContent: v }); } } function sanitizeTags(tags) { return tags.filter((t) => { const { innerHTML, tag, props } = t; if (!ValidHeadTags.has(tag) || !Object.keys(props).length && !innerHTML && !t.textContent) return false; if (tag === "meta" && !props.content && !props["http-equiv"] && !props.charset) return false; if (tag === "script" && innerHTML) { t.innerHTML = String(props.type).endsWith("json") ? (typeof innerHTML === "string" ? innerHTML : JSON.stringify(innerHTML)).replace(LT_RE, "\\u003C") : typeof innerHTML === "string" ? innerHTML.replace(SCRIPT_END_RE, "<\\/script") : innerHTML; t._d = dedupeKey(t); } return true; }); } function resolveTags(head, options) { const weightFn = options?.tagWeight ?? head.resolvedOptions._tagWeight ?? (() => 100); const ctx = { tagMap: new Map(), tags: [] }; const entries = [...head.entries.values()]; for (const e of entries) { if (e._pending !== void 0) { e.input = e._pending; delete e._pending; delete e._tags; } } callHook(head, "entries:resolve", { entries, ...ctx }); for (const e of entries) { if (!e._tags) { const normalizeCtx = { tags: normalizeEntryToTags(e.input, head.resolvedOptions.propResolvers || []).map((t) => Object.assign(t, e.options)), entry: e }; callHook(head, "entries:normalize", normalizeCtx); e._tags = normalizeCtx.tags.map((t, i) => { t._w = weightFn(t); t._p = (e._i << 10) + i; t._d = dedupeKey(t); if (!t._d) t._h = hashTag(t); return t; }); } } ctx.tags = entries.flatMap((e) => (e._tags || []).map((t) => ({ ...t, props: { ...t.props } }))); const hasFlatMeta = dedupeTags(ctx); resolveTitleTemplate(ctx, head); ctx.tags = [...ctx.tagMap.values()]; if (hasFlatMeta) ctx.tags = ctx.tags.flat().sort(sortTags); callHook(head, "tags:beforeResolve", ctx); callHook(head, "tags:resolve", ctx); callHook(head, "tags:afterResolve", ctx); return sanitizeTags(ctx.tags); } const WHITESPACE_RE = /\s+/; function createDomRenderer(options = {}) { return (head) => _renderDOMHead(head, options); } function _renderDOMHead(head, options = {}) { const dom = options.document || head.resolvedOptions.document; if (!dom || !head.dirty && ![...head.entries.values()].some((e) => e._pending !== void 0)) return false; const beforeRenderCtx = { shouldRender: true, tags: [] }; callHook(head, "dom:beforeRender", beforeRenderCtx); if (!beforeRenderCtx.shouldRender || head._du) return false; head._du = true; let state = head._dom; if (!state) { state = { _t: dom.title, _e: new Map([["htmlAttrs", dom.documentElement], ["bodyAttrs", dom.body]]), _p: {}, _s: {} }; for (const el of [...dom.body.children, ...dom.head.children]) { const tag = el.tagName.toLowerCase(); if (!HasElementTags.has(tag)) continue; const props = { innerHTML: el.innerHTML }; for (const n of el.getAttributeNames()) props[n] = el.getAttribute(n); const next = normalizeProps({ tag, props: {} }, props); next.key = el.getAttribute("data-hid") || void 0; let k = next._d = dedupeKey(next) || hashTag(next); let c = 1; while (state._e.has(k)) k = `${next._d}:${c++}`; state._e.set(k, el); } for (const entry of head.entries.values()) { if (entry._o !== void 0) { const orig = entry._o; for (const t of ["bodyAttrs", "htmlAttrs"]) { const cls = orig[t]?.class; if (typeof cls === "string") { const $el = state._e.get(t); for (const c of cls.split(WHITESPACE_RE)) { if (c) state._p[`${t}:attr:class:${c}`] = () => $el.classList.remove(c); } } } delete entry._o; } } } else { state._p = { ...state._s }; } state._s = {}; function track(id, scope, fn) { const k = `${id}:${scope}`; state._s[k] = fn; delete state._p[k]; } function trackCtx({ id, $el, tag }) { const isAttr = tag.tag.endsWith("Attrs"); state._e.set(id, $el); if (!isAttr) { if (tag.textContent && tag.textContent !== $el.textContent) $el.textContent = tag.textContent; if (tag.innerHTML && tag.innerHTML !== $el.innerHTML) $el.innerHTML = tag.innerHTML; track(id, "el", () => { $el?.remove(); state._e.delete(id); }); } for (const k in tag.props) { const v = tag.props[k]; if (k[0] === "o" && k[1] === "n" && typeof v === "function") { const ev = k.slice(2); if ($el?.dataset?.[`${k}fired`]) v.call($el, new Event(ev)); if ($el.getAttribute(`data-${k}`) !== "") { (tag.tag === "bodyAttrs" ? dom.defaultView : $el).addEventListener(ev, v.bind($el)); $el.setAttribute(`data-${k}`, ""); } continue; } const ck = `attr:${k}`; if (k === "class" && v) { for (const c of v) { if (isAttr) track(id, `${ck}:${c}`, () => $el.classList.remove(c)); if (!$el.classList.contains(c)) $el.classList.add(c); } } else if (k === "style" && v) { for (const [sk, sv] of v) { track(id, `${ck}:${sk}`, () => $el.style.removeProperty(sk)); $el.style.setProperty(sk, sv); } } else if (v !== false && v !== null) { if ($el.getAttribute(k) !== v) $el.setAttribute(k, v === true ? "" : String(v)); if (isAttr) track(id, ck, () => $el.removeAttribute(k)); } } } const pending = []; const frag = {}; const rawTags = resolveTags(head, options.tagWeight ? { tagWeight: options.tagWeight } : void 0); const tags = []; const dupeKeyCounter = new Map(); for (const tag of rawTags) { const count = dupeKeyCounter.get(tag._d) || 0; const id = (count ? `${tag._d}:${count}` : tag._d) || tag._h; const ctx = { tag, id, shouldRender: true }; if (tag._d && isMetaArrayDupeKey(tag._d)) dupeKeyCounter.set(tag._d, count + 1); tags.push(ctx); if (tag.tag === "title") { dom.title = tag.textContent; track("title", "", () => dom.title = state._t); continue; } ctx.$el = state._e.get(id); if (ctx.$el) trackCtx(ctx); else if (HasElementTags.has(tag.tag)) pending.push(ctx); } for (const ctx of pending) { ctx.$el = dom.createElement(ctx.tag.tag); trackCtx(ctx); (frag[ctx.tag.tagPosition || "head"] ??= dom.createDocumentFragment()).appendChild(ctx.$el); } if (frag.head) dom.head.appendChild(frag.head); if (frag.bodyOpen) dom.body.insertBefore(frag.bodyOpen, dom.body.firstChild); if (frag.bodyClose) dom.body.appendChild(frag.bodyClose); for (const k in state._p) state._p[k](); head._dom = state; callHook(head, "dom:rendered", { renders: tags }); head._du = false; head.dirty = false; return true; } function registerPlugin(head, p) { const plugin = typeof p === "function" ? p(head) : p; const key = plugin.key || String(head.plugins.size + 1); if (!head.plugins.get(key)) { head.plugins.set(key, plugin); for (const k in plugin.hooks || {}) head.hooks?.hook(k, plugin.hooks[k]); } } function createUnhead(renderer, resolvedOptions = {}) { const ssr = !resolvedOptions.document; const entries = new Map(); const plugins = new Map(); const head = { _entryCount: 1, plugins, resolvedOptions, ssr, entries, render: () => renderer(head), use: (p) => registerPlugin(head, p), push(input, _options) { const _i = _options?._index ?? head._entryCount++; const options = _options ? { ..._options } : {}; delete options.head; delete options.onRendered; const entry = { _i, input, options }; entries.set(_i, entry); const active = { _i, dispose() { entries.delete(_i); }, patch(input2) { if (ssr) { entry.input = input2; delete entry._tags; } else { entry._pending = input2; } if (!entries.has(_i)) entries.set(_i, entry); } }; return active; } }; resolvedOptions.init?.forEach((e) => e && head.push(e)); return head; } const DEFAULT_STREAM_KEY = "__unhead__"; function init(options = {}) { const { streamKey = DEFAULT_STREAM_KEY } = options; const win = typeof window !== "undefined" ? window : void 0; if (!win) return; const queue = win[streamKey]; if (queue?._head) return queue._head; const doc = typeof document !== "undefined" ? document : void 0; const head = createUnhead(createDomRenderer(), { document: doc }); let hydrationLocked = true; queueMicrotask(() => { hydrationLocked = false; }); function pushStreamed(entry) { const active = head.push(entry); const stored = head.entries.get(active._i); if (stored) stored._streamed = true; } if (queue?._q) { for (const entries of queue._q) { for (const entry of entries) { pushStreamed(entry); } } head.dirty = true; head.render(); } win[streamKey] = { _q: queue?._q || [], _head: head, _hydrationLocked: () => hydrationLocked, push: (entries) => { for (const entry of entries) { pushStreamed(entry); } head.dirty = true; head.render(); } }; return head; } init(); exports.init = init; return exports; })({});
|
|
1
|
+
var __unhead_iife__ = (function (exports) { 'use strict'; const DupeableTags = new Set(["link", "style", "script", "noscript"]); const TagsWithInnerContent = new Set(["title", "titleTemplate", "script", "style", "noscript"]); const HasElementTags = new Set(["base", "meta", "link", "style", "script", "noscript"]); const ValidHeadTags = new Set(["title", "base", "htmlAttrs", "bodyAttrs", "meta", "link", "style", "script", "noscript"]); const UniqueTags = new Set(["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs", "templateParams"]); const TagConfigKeys = new Set(["key", "tagPosition", "tagPriority", "tagDuplicateStrategy", "innerHTML", "textContent", "processTemplateParams"]); const UsesMergeStrategy = new Set(["templateParams", "htmlAttrs", "bodyAttrs"]); const MetaTagsArrayable = new Set([ "theme-color", "google-site-verification", "og", "article", "book", "profile", "twitter", "author" ]); function callHook(head, hook, ctx) { return head.hooks?.callHook(hook, ctx); } const META_NOREWRITE_RE = /^(?:viewport|description|keywords|robots)$/; function isMetaArrayDupeKey(v) { return MetaTagsArrayable.has(v.split(":")[1]); } function dedupeKey(tag) { const { props, tag: t, key } = tag; if (UniqueTags.has(t)) return t; if (t === "link" && props.rel === "canonical") return "canonical"; if (t === "link" && props.rel === "alternate") { const altKey = props.hreflang || props.type; if (altKey) return `alternate:${altKey}`; } if (props.charset) return "charset"; if (t === "meta") { for (const n of ["name", "property", "http-equiv"]) { const v = props[n]; if (v !== void 0) return `meta:${v}${(typeof v !== "string" || !v.includes(":")) && !META_NOREWRITE_RE.test(v) && key ? `:key:${key}` : ""}`; } } if (key) return `${t}:key:${key}`; if (props.id) return `${t}:id:${props.id}`; if (t === "link" && props.rel === "alternate") return `alternate:${props.href || ""}`; return TagsWithInnerContent.has(t) && (tag.textContent || tag.innerHTML) ? `${t}:content:${tag.textContent || tag.innerHTML}` : void 0; } function hashTag(tag) { return tag._h || tag._d || tag.textContent || tag.innerHTML || `${tag.tag}:${Object.entries(tag.props).map(([k, v]) => `${k}:${String(v)}`).join()}`; } function walkResolver(val, resolve, key) { if (key === "_resolver") return val; if (typeof val === "function" && (!key || key !== "titleTemplate" && !key.startsWith("on"))) val = val(); const v = resolve ? resolve(key, val) : val; if (Array.isArray(v)) return v.map((r) => walkResolver(r, resolve)); if (v?.constructor === Object) { const next = {}; for (const k in v) { if (k === "__proto__" || k === "constructor" || k === "prototype") continue; next[k] = walkResolver(v[k], resolve, k); } return next; } return v; } function normalizeStyleClassProps(key, value) { const isStyle = key === "style"; const store = isStyle ? new Map() : new Set(); const add = (v) => { if (!v) return; if (isStyle) { const i = v.indexOf(":"); i > 0 && store.set(v.slice(0, i).trim(), v.slice(i + 1).trim()); } else { v.split(" ").forEach((c) => c && store.add(c)); } }; if (typeof value === "string") { (isStyle ? value.split(";") : [value]).forEach(add); } else if (Array.isArray(value)) { value.forEach(add); } else if (value && typeof value === "object") { for (const k in value) { const v = value[k]; v && v !== "false" && (isStyle ? store.set(k.trim(), String(v)) : add(k)); } } return store; } function normalizeProps(tag, input) { tag.props = tag.props || {}; if (!input) return tag; if (tag.tag === "templateParams") { tag.props = input; return tag; } const isHtmlTag = HasElementTags.has(tag.tag) || tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs"; for (const prop in input) { if (prop === "__proto__" || prop === "constructor" || prop === "prototype") continue; const value = input[prop]; if (value === null) { tag.props[prop] = null; } else if (prop === "class" || prop === "style") { tag.props[prop] = normalizeStyleClassProps(prop, value); } else if (TagConfigKeys.has(prop)) { if ((prop === "textContent" || prop === "innerHTML") && typeof value === "object") { const type = input.type || "application/json"; if (type.endsWith("json") || type === "speculationrules" || type === "importmap") { tag.props.type = input.type = type; tag[prop] = JSON.stringify(value); } } else { tag[prop] = value; } } else if (value !== void 0) { const isData = prop.startsWith("data-"); const key = isHtmlTag && !isData ? prop.toLowerCase() : prop; const str = String(value); const isMeta = tag.tag === "meta" && key === "content"; tag.props[key] = str === "true" || str === "" ? isData || isMeta ? str : true : !value && isData && str === "false" ? "false" : value; } } return tag; } function normalizeTag(tagName, _input) { const input = typeof _input === "object" && typeof _input !== "function" ? _input : { [tagName === "script" || tagName === "noscript" || tagName === "style" ? "innerHTML" : "textContent"]: _input }; const tag = normalizeProps({ tag: tagName, props: {} }, input); if (tag.key && DupeableTags.has(tag.tag)) tag.props["data-hid"] = tag._h = tag.key; if (tag.tag === "script" && typeof tag.innerHTML === "object") { tag.innerHTML = JSON.stringify(tag.innerHTML); tag.props.type = tag.props.type || "application/json"; } return Array.isArray(tag.props.content) ? tag.props.content.map((v) => ({ ...tag, props: { ...tag.props, content: v } })) : tag; } function normalizeEntryToTags(input, propResolvers) { if (!input) return []; if (typeof input === "function") input = input(); const resolvers = (key, val) => { for (const r of propResolvers) val = r(key, val); return val; }; input = walkResolver(resolvers(void 0, input), resolvers); const tags = []; for (const key in input) { const value = input[key]; if (value !== void 0) { for (const v of Array.isArray(value) ? value : [value]) tags.push(normalizeTag(key, v)); } } return tags.flat(); } const LT_RE = /</g; const SCRIPT_END_RE = /<\/script/g; const sortTags = (a, b) => a._w === b._w ? a._p - b._p : a._w - b._w; function dedupeTags(ctx) { let hasFlatMeta = false; for (const next of ctx.tags.sort(sortTags)) { const k = next._d || hashTag(next); const prev = ctx.tagMap.get(k); if (!prev) { ctx.tagMap.set(k, next); continue; } const strategy = next.tagDuplicateStrategy || (UsesMergeStrategy.has(next.tag) ? "merge" : null) || (next.key && next.key === prev.key ? "merge" : null); if (strategy === "merge") { const props = { ...prev.props }; for (const p in next.props) { props[p] = p === "style" ? new Map([...prev.props.style || new Map(), ...next.props[p]]) : p === "class" ? new Set([...prev.props.class || [], ...next.props[p]]) : next.props[p]; } ctx.tagMap.set(k, { ...next, props }); } else if (next._p >> 10 === prev._p >> 10 && next.tag === "meta" && isMetaArrayDupeKey(k)) { ctx.tagMap.set(k, Object.assign([...Array.isArray(prev) ? prev : [prev], next], next)); hasFlatMeta = true; } else if (next._w === prev._w ? next._p > prev._p : next._w < prev._w) { ctx.tagMap.set(k, next); } } return hasFlatMeta; } function resolveTitleTemplate(ctx, head) { const title = ctx.tagMap.get("title"); const tpl = ctx.tagMap.get("titleTemplate"); head._title = title?.textContent; if (!tpl) return; const fn = tpl.textContent; head._titleTemplate = fn; if (!fn) return; let v = typeof fn === "function" ? fn(title?.textContent) : fn; if (typeof v === "string" && !head.plugins.has("template-params")) v = v.replace("%s", title?.textContent || ""); if (title) { v === null ? ctx.tagMap.delete("title") : ctx.tagMap.set("title", { ...title, textContent: v }); } else { ctx.tagMap.set("titleTemplate", { ...tpl, tag: "title", textContent: v }); } } function sanitizeTags(tags) { return tags.filter((t) => { const { innerHTML, tag, props } = t; if (!ValidHeadTags.has(tag) || !Object.keys(props).length && !innerHTML && !t.textContent) return false; if (tag === "meta" && !props.content && !props["http-equiv"] && !props.charset) return false; if (tag === "script" && (innerHTML || t.textContent)) { const type = String(props.type); const isJsonLike = type.endsWith("json") || type === "importmap" || type === "speculationrules"; const escape = (content) => isJsonLike ? (typeof content === "string" ? content : JSON.stringify(content)).replace(LT_RE, "\\u003C") : typeof content === "string" ? content.replace(SCRIPT_END_RE, "<\\/script") : content; if (innerHTML) t.innerHTML = escape(innerHTML); if (t.textContent) t.textContent = escape(t.textContent); t._d = dedupeKey(t); } return true; }); } function resolveTags(head, options) { const weightFn = options?.tagWeight ?? head.resolvedOptions._tagWeight ?? (() => 100); const ctx = { tagMap: new Map(), tags: [] }; const entries = [...head.entries.values()]; for (const e of entries) { if (e._pending !== void 0) { e.input = e._pending; delete e._pending; delete e._tags; } } callHook(head, "entries:resolve", { entries, ...ctx }); for (const e of entries) { if (!e._tags) { const normalizeCtx = { tags: normalizeEntryToTags(e.input, head.resolvedOptions.propResolvers || []).map((t) => Object.assign(t, e.options)), entry: e }; callHook(head, "entries:normalize", normalizeCtx); e._tags = normalizeCtx.tags.map((t, i) => { t._w = weightFn(t); t._p = (e._i << 10) + i; t._d = dedupeKey(t); if (!t._d) t._h = hashTag(t); return t; }); } } ctx.tags = entries.flatMap((e) => (e._tags || []).map((t) => ({ ...t, props: { ...t.props } }))); const hasFlatMeta = dedupeTags(ctx); resolveTitleTemplate(ctx, head); ctx.tags = [...ctx.tagMap.values()]; if (hasFlatMeta) ctx.tags = ctx.tags.flat().sort(sortTags); callHook(head, "tags:beforeResolve", ctx); callHook(head, "tags:resolve", ctx); callHook(head, "tags:afterResolve", ctx); return sanitizeTags(ctx.tags); } const WHITESPACE_RE = /\s+/; function createDomRenderer(options = {}) { return (head) => _renderDOMHead(head, options); } function _renderDOMHead(head, options = {}) { const dom = options.document || head.resolvedOptions.document; if (!dom || !head.dirty && ![...head.entries.values()].some((e) => e._pending !== void 0)) return false; const beforeRenderCtx = { shouldRender: true, tags: [] }; callHook(head, "dom:beforeRender", beforeRenderCtx); if (!beforeRenderCtx.shouldRender || head._du) return false; head._du = true; let state = head._dom; if (!state) { state = { _t: dom.title, _e: new Map([["htmlAttrs", dom.documentElement], ["bodyAttrs", dom.body]]), _p: {}, _s: {} }; for (const el of [...dom.body.children, ...dom.head.children]) { const tag = el.tagName.toLowerCase(); if (!HasElementTags.has(tag)) continue; const props = { innerHTML: el.innerHTML }; for (const n of el.getAttributeNames()) props[n] = el.getAttribute(n); const next = normalizeProps({ tag, props: {} }, props); next.key = el.getAttribute("data-hid") || void 0; let k = next._d = dedupeKey(next) || hashTag(next); let c = 1; while (state._e.has(k)) k = `${next._d}:${c++}`; state._e.set(k, el); } for (const entry of head.entries.values()) { if (entry._o !== void 0) { const orig = entry._o; for (const t of ["bodyAttrs", "htmlAttrs"]) { const cls = orig[t]?.class; if (typeof cls === "string") { const $el = state._e.get(t); for (const c of cls.split(WHITESPACE_RE)) { if (c) state._p[`${t}:attr:class:${c}`] = () => $el.classList.remove(c); } } } delete entry._o; } } } else { state._p = { ...state._s }; } state._s = {}; function track(id, scope, fn) { const k = `${id}:${scope}`; state._s[k] = fn; delete state._p[k]; } function trackCtx({ id, $el, tag }) { const isAttr = tag.tag.endsWith("Attrs"); state._e.set(id, $el); if (!isAttr) { if (tag.textContent && tag.textContent !== $el.textContent) $el.textContent = tag.textContent; if (tag.innerHTML && tag.innerHTML !== $el.innerHTML) $el.innerHTML = tag.innerHTML; track(id, "el", () => { $el?.remove(); state._e.delete(id); }); } for (const k in tag.props) { const v = tag.props[k]; if (k[0] === "o" && k[1] === "n" && typeof v === "function") { const ev = k.slice(2); if ($el?.dataset?.[`${k}fired`]) v.call($el, new Event(ev)); if ($el.getAttribute(`data-${k}`) !== "") { (tag.tag === "bodyAttrs" ? dom.defaultView : $el).addEventListener(ev, v.bind($el)); $el.setAttribute(`data-${k}`, ""); } continue; } const ck = `attr:${k}`; if (k === "class" && v) { for (const c of v) { if (isAttr) track(id, `${ck}:${c}`, () => $el.classList.remove(c)); if (!$el.classList.contains(c)) $el.classList.add(c); } } else if (k === "style" && v) { for (const [sk, sv] of v) { track(id, `${ck}:${sk}`, () => $el.style.removeProperty(sk)); $el.style.setProperty(sk, sv); } } else if (v !== false && v !== null) { if ($el.getAttribute(k) !== v) $el.setAttribute(k, v === true ? "" : String(v)); if (isAttr) track(id, ck, () => $el.removeAttribute(k)); } } } const pending = []; const frag = {}; const rawTags = resolveTags(head, options.tagWeight ? { tagWeight: options.tagWeight } : void 0); const tags = []; const dupeKeyCounter = new Map(); for (const tag of rawTags) { const count = dupeKeyCounter.get(tag._d) || 0; const id = (count ? `${tag._d}:${count}` : tag._d) || tag._h; const ctx = { tag, id, shouldRender: true }; if (tag._d && isMetaArrayDupeKey(tag._d)) dupeKeyCounter.set(tag._d, count + 1); tags.push(ctx); if (tag.tag === "title") { dom.title = tag.textContent; track("title", "", () => dom.title = state._t); continue; } ctx.$el = state._e.get(id); if (ctx.$el) trackCtx(ctx); else if (HasElementTags.has(tag.tag)) pending.push(ctx); } for (const ctx of pending) { ctx.$el = dom.createElement(ctx.tag.tag); trackCtx(ctx); (frag[ctx.tag.tagPosition || "head"] ??= dom.createDocumentFragment()).appendChild(ctx.$el); } if (frag.head) dom.head.appendChild(frag.head); if (frag.bodyOpen) dom.body.insertBefore(frag.bodyOpen, dom.body.firstChild); if (frag.bodyClose) dom.body.appendChild(frag.bodyClose); for (const k in state._p) state._p[k](); head._dom = state; callHook(head, "dom:rendered", { renders: tags }); head._du = false; head.dirty = false; return true; } function registerPlugin(head, p) { const plugin = typeof p === "function" ? p(head) : p; const key = plugin.key || String(head.plugins.size + 1); if (!head.plugins.get(key)) { head.plugins.set(key, plugin); for (const k in plugin.hooks || {}) head.hooks?.hook(k, plugin.hooks[k]); } } function createUnhead(renderer, resolvedOptions = {}) { const ssr = !resolvedOptions.document; const entries = new Map(); const plugins = new Map(); const head = { _entryCount: 1, plugins, resolvedOptions, ssr, entries, render: () => renderer(head), use: (p) => registerPlugin(head, p), push(input, _options) { const _i = _options?._index ?? head._entryCount++; const options = _options ? { ..._options } : {}; delete options.head; delete options.onRendered; const entry = { _i, input, options }; entries.set(_i, entry); const active = { _i, dispose() { entries.delete(_i); }, patch(input2) { if (ssr) { entry.input = input2; delete entry._tags; } else { entry._pending = input2; } if (!entries.has(_i)) entries.set(_i, entry); } }; return active; } }; resolvedOptions.init?.forEach((e) => e && head.push(e)); return head; } const DEFAULT_STREAM_KEY = "__unhead__"; function init(options = {}) { const { streamKey = DEFAULT_STREAM_KEY } = options; const win = typeof window !== "undefined" ? window : void 0; if (!win) return; const queue = win[streamKey]; if (queue?._head) return queue._head; const doc = typeof document !== "undefined" ? document : void 0; const head = createUnhead(createDomRenderer(), { document: doc }); let hydrationLocked = true; queueMicrotask(() => { hydrationLocked = false; }); function pushStreamed(entry) { const active = head.push(entry); const stored = head.entries.get(active._i); if (stored) stored._streamed = true; } if (queue?._q) { for (const entries of queue._q) { for (const entry of entries) { pushStreamed(entry); } } head.dirty = true; head.render(); } win[streamKey] = { _q: queue?._q || [], _head: head, _hydrationLocked: () => hydrationLocked, push: (entries) => { for (const entry of entries) { pushStreamed(entry); } head.dirty = true; head.render(); } }; return head; } init(); exports.init = init; return exports; })({});
|