@fuzdev/fuz_ui 0.206.7 → 0.206.9
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/README.md +3 -3
- package/dist/Alert.svelte +21 -25
- package/dist/Alert.svelte.d.ts.map +1 -1
- package/dist/ApiDeclarationList.svelte +2 -2
- package/dist/ApiDeclarationList.svelte.d.ts.map +1 -1
- package/dist/ApiIndex.svelte +4 -4
- package/dist/ApiIndex.svelte.d.ts.map +1 -1
- package/dist/ApiModule.svelte +13 -10
- package/dist/ApiModule.svelte.d.ts.map +1 -1
- package/dist/ApiModulesList.svelte +2 -2
- package/dist/ApiModulesList.svelte.d.ts.map +1 -1
- package/dist/Breadcrumb.svelte +31 -19
- package/dist/Breadcrumb.svelte.d.ts.map +1 -1
- package/dist/Card.svelte +17 -17
- package/dist/Card.svelte.d.ts.map +1 -1
- package/dist/ColorSchemeInput.svelte +6 -6
- package/dist/ColorSchemeInput.svelte.d.ts.map +1 -1
- package/dist/Contextmenu.svelte +6 -4
- package/dist/Contextmenu.svelte.d.ts.map +1 -1
- package/dist/ContextmenuEntry.svelte +8 -8
- package/dist/ContextmenuEntry.svelte.d.ts.map +1 -1
- package/dist/ContextmenuIcon.svelte +3 -3
- package/dist/ContextmenuIcon.svelte.d.ts.map +1 -1
- package/dist/ContextmenuLinkEntry.svelte +14 -14
- package/dist/ContextmenuLinkEntry.svelte.d.ts.map +1 -1
- package/dist/ContextmenuMenu.svelte +10 -10
- package/dist/ContextmenuMenu.svelte.d.ts.map +1 -1
- package/dist/ContextmenuRoot.svelte +7 -7
- package/dist/ContextmenuRootForSafariCompatibility.svelte +15 -15
- package/dist/ContextmenuSeparator.svelte +2 -2
- package/dist/ContextmenuSubmenu.svelte +15 -12
- package/dist/ContextmenuSubmenu.svelte.d.ts.map +1 -1
- package/dist/ContextmenuTextEntry.svelte +4 -4
- package/dist/ContextmenuTextEntry.svelte.d.ts.map +1 -1
- package/dist/CopyToClipboard.svelte +7 -7
- package/dist/CopyToClipboard.svelte.d.ts.map +1 -1
- package/dist/DeclarationDetail.svelte +35 -28
- package/dist/DeclarationDetail.svelte.d.ts.map +1 -1
- package/dist/DeclarationLink.svelte +7 -7
- package/dist/DeclarationLink.svelte.d.ts.map +1 -1
- package/dist/Details.svelte +3 -3
- package/dist/Details.svelte.d.ts.map +1 -1
- package/dist/Dialog.svelte +7 -7
- package/dist/Dialog.svelte.d.ts.map +1 -1
- package/dist/DialogContent.svelte +6 -6
- package/dist/DialogContent.svelte.d.ts.map +1 -1
- package/dist/Docs.svelte +14 -12
- package/dist/Docs.svelte.d.ts.map +1 -1
- package/dist/DocsContent.svelte +4 -4
- package/dist/DocsContent.svelte.d.ts.map +1 -1
- package/dist/DocsFooter.svelte +7 -8
- package/dist/DocsFooter.svelte.d.ts.map +1 -1
- package/dist/DocsLink.svelte +24 -21
- package/dist/DocsLink.svelte.d.ts.map +1 -1
- package/dist/DocsList.svelte +3 -3
- package/dist/DocsList.svelte.d.ts.map +1 -1
- package/dist/DocsMenu.svelte +13 -10
- package/dist/DocsMenu.svelte.d.ts.map +1 -1
- package/dist/DocsMenuHeader.svelte +2 -2
- package/dist/DocsMenuHeader.svelte.d.ts.map +1 -1
- package/dist/DocsPageLinks.svelte +9 -7
- package/dist/DocsPageLinks.svelte.d.ts.map +1 -1
- package/dist/DocsPrimaryNav.svelte +5 -5
- package/dist/DocsPrimaryNav.svelte.d.ts.map +1 -1
- package/dist/DocsSearch.svelte +3 -3
- package/dist/DocsSearch.svelte.d.ts.map +1 -1
- package/dist/DocsSecondaryNav.svelte +3 -3
- package/dist/DocsSecondaryNav.svelte.d.ts.map +1 -1
- package/dist/DocsTertiaryNav.svelte +8 -8
- package/dist/DocsTertiaryNav.svelte.d.ts.map +1 -1
- package/dist/EcosystemLinks.svelte +3 -3
- package/dist/EcosystemLinks.svelte.d.ts.map +1 -1
- package/dist/EcosystemLinksPanel.svelte +2 -2
- package/dist/EcosystemLinksPanel.svelte.d.ts.map +1 -1
- package/dist/GithubLink.svelte +10 -10
- package/dist/GithubLink.svelte.d.ts.map +1 -1
- package/dist/Glyph.svelte +4 -2
- package/dist/Glyph.svelte.d.ts.map +1 -1
- package/dist/Hashlink.svelte +5 -5
- package/dist/Hashlink.svelte.d.ts.map +1 -1
- package/dist/HueInput.svelte +5 -5
- package/dist/HueInput.svelte.d.ts.map +1 -1
- package/dist/ImgOrSvg.svelte +20 -20
- package/dist/ImgOrSvg.svelte.d.ts.map +1 -1
- package/dist/LibraryDetail.svelte +16 -16
- package/dist/LibraryDetail.svelte.d.ts.map +1 -1
- package/dist/LibrarySummary.svelte +10 -8
- package/dist/LibrarySummary.svelte.d.ts.map +1 -1
- package/dist/MdnLink.svelte +8 -8
- package/dist/MdnLink.svelte.d.ts.map +1 -1
- package/dist/ModuleLink.svelte +5 -5
- package/dist/ModuleLink.svelte.d.ts.map +1 -1
- package/dist/PasteFromClipboard.svelte +1 -1
- package/dist/PasteFromClipboard.svelte.d.ts.map +1 -1
- package/dist/PendingAnimation.svelte +12 -11
- package/dist/PendingAnimation.svelte.d.ts.map +1 -1
- package/dist/PendingButton.svelte +3 -3
- package/dist/PendingButton.svelte.d.ts.map +1 -1
- package/dist/ProjectActivityChart.svelte +137 -0
- package/dist/ProjectActivityChart.svelte.d.ts +30 -0
- package/dist/ProjectActivityChart.svelte.d.ts.map +1 -0
- package/dist/ProjectLinks.svelte +29 -48
- package/dist/ProjectLinks.svelte.d.ts.map +1 -1
- package/dist/Redirect.svelte +12 -8
- package/dist/Redirect.svelte.d.ts.map +1 -1
- package/dist/Sparkline.svelte +131 -0
- package/dist/Sparkline.svelte.d.ts +42 -0
- package/dist/Sparkline.svelte.d.ts.map +1 -0
- package/dist/Spiders.svelte +5 -5
- package/dist/Spiders.svelte.d.ts.map +1 -1
- package/dist/StyleVariableButton.svelte +6 -6
- package/dist/StyleVariableButton.svelte.d.ts.map +1 -1
- package/dist/Svg.svelte +5 -5
- package/dist/Svg.svelte.d.ts.map +1 -1
- package/dist/Teleport.svelte +2 -2
- package/dist/Teleport.svelte.d.ts.map +1 -1
- package/dist/ThemeInput.svelte +10 -8
- package/dist/ThemeInput.svelte.d.ts.map +1 -1
- package/dist/ThemeRoot.svelte +10 -11
- package/dist/ThemeRoot.svelte.d.ts.map +1 -1
- package/dist/TomeContent.svelte +11 -11
- package/dist/TomeContent.svelte.d.ts.map +1 -1
- package/dist/TomeHeader.svelte +6 -6
- package/dist/TomeLink.svelte +7 -7
- package/dist/TomeLink.svelte.d.ts.map +1 -1
- package/dist/TomeSection.svelte +8 -8
- package/dist/TomeSection.svelte.d.ts.map +1 -1
- package/dist/TomeSectionHeader.svelte +12 -12
- package/dist/TomeSectionHeader.svelte.d.ts.map +1 -1
- package/dist/TypeLink.svelte +11 -11
- package/dist/TypeLink.svelte.d.ts.map +1 -1
- package/dist/alert.js +1 -1
- package/dist/api_search.svelte.d.ts.map +1 -1
- package/dist/api_search.svelte.js +5 -7
- package/dist/autofocus.svelte.d.ts.map +1 -1
- package/dist/context_helpers.js +1 -1
- package/dist/contextmenu_helpers.d.ts.map +1 -1
- package/dist/contextmenu_helpers.js +3 -3
- package/dist/contextmenu_state.svelte.d.ts.map +1 -1
- package/dist/contextmenu_state.svelte.js +4 -4
- package/dist/csp.d.ts.map +1 -1
- package/dist/csp.js +27 -27
- package/dist/csp_of_fuzdev.d.ts.map +1 -1
- package/dist/csp_of_fuzdev.js +1 -1
- package/dist/declaration.svelte.d.ts +44 -256
- package/dist/declaration.svelte.d.ts.map +1 -1
- package/dist/declaration.svelte.js +132 -52
- package/dist/declaration_contextmenu.d.ts.map +1 -1
- package/dist/declaration_contextmenu.js +2 -2
- package/dist/docs_helpers.svelte.d.ts.map +1 -1
- package/dist/icons.js +200 -200
- package/dist/intersect.svelte.d.ts.map +1 -1
- package/dist/library.svelte.d.ts +31 -18
- package/dist/library.svelte.d.ts.map +1 -1
- package/dist/library.svelte.js +76 -21
- package/dist/logos.js +42 -42
- package/dist/module.svelte.d.ts +30 -37
- package/dist/module.svelte.d.ts.map +1 -1
- package/dist/module.svelte.js +88 -35
- package/dist/module_contextmenu.d.ts.map +1 -1
- package/dist/module_contextmenu.js +2 -2
- package/dist/project_stats.d.ts +121 -0
- package/dist/project_stats.d.ts.map +1 -0
- package/dist/project_stats.js +153 -0
- package/dist/project_stats_data.d.ts +3 -0
- package/dist/project_stats_data.d.ts.map +1 -0
- package/dist/project_stats_data.js +469 -0
- package/dist/project_stats_update.task.d.ts +4 -0
- package/dist/project_stats_update.task.d.ts.map +1 -0
- package/dist/project_stats_update.task.js +50 -0
- package/dist/projects.d.ts +17 -0
- package/dist/projects.d.ts.map +1 -0
- package/dist/projects.js +20 -0
- package/dist/publish.task.d.ts +3 -0
- package/dist/publish.task.d.ts.map +1 -0
- package/dist/publish.task.js +23 -0
- package/dist/site.svelte.d.ts.map +1 -1
- package/dist/sparkline.d.ts +102 -0
- package/dist/sparkline.d.ts.map +1 -0
- package/dist/sparkline.js +63 -0
- package/dist/style_variable_helpers.svelte.d.ts.map +1 -1
- package/dist/svg.d.ts.map +1 -1
- package/dist/theme_state.svelte.d.ts.map +1 -1
- package/dist/theme_state.svelte.js +1 -1
- package/dist/tome.d.ts.map +1 -1
- package/dist/tome.js +1 -1
- package/dist/vite_plugin_pkg_json.d.ts.map +1 -1
- package/dist/vite_plugin_pkg_json.js +1 -1
- package/package.json +3 -22
- package/src/lib/alert.ts +3 -3
- package/src/lib/api_search.svelte.ts +9 -11
- package/src/lib/autofocus.svelte.ts +2 -2
- package/src/lib/context_helpers.ts +2 -2
- package/src/lib/contextmenu_helpers.ts +21 -21
- package/src/lib/contextmenu_state.svelte.ts +32 -34
- package/src/lib/csp.ts +42 -54
- package/src/lib/csp_of_fuzdev.ts +2 -2
- package/src/lib/declaration.svelte.ts +157 -62
- package/src/lib/declaration_contextmenu.ts +5 -5
- package/src/lib/dialog.ts +1 -1
- package/src/lib/docs_helpers.svelte.ts +9 -9
- package/src/lib/icons.ts +205 -205
- package/src/lib/intersect.svelte.ts +5 -5
- package/src/lib/library.svelte.ts +103 -36
- package/src/lib/library_helpers.ts +2 -2
- package/src/lib/logos.ts +43 -43
- package/src/lib/module.svelte.ts +98 -49
- package/src/lib/module_contextmenu.ts +4 -4
- package/src/lib/project_stats.ts +220 -0
- package/src/lib/project_stats_data.ts +472 -0
- package/src/lib/project_stats_update.task.ts +53 -0
- package/src/lib/projects.ts +49 -0
- package/src/lib/publish.task.ts +22 -0
- package/src/lib/site.svelte.ts +5 -5
- package/src/lib/sparkline.ts +173 -0
- package/src/lib/storage.ts +2 -2
- package/src/lib/style_variable_helpers.svelte.ts +2 -2
- package/src/lib/svg.ts +2 -2
- package/src/lib/theme_state.svelte.ts +8 -8
- package/src/lib/tome.ts +8 -8
- package/src/lib/vite_plugin_pkg_json.ts +8 -8
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {onDestroy, type Snippet} from 'svelte';
|
|
2
|
-
import type {Result} from '@fuzdev/fuz_util/result.ts';
|
|
3
|
-
import {is_promise} from '@fuzdev/fuz_util/async.ts';
|
|
4
|
-
import {BROWSER, DEV} from 'esm-env';
|
|
5
|
-
import type {SvelteHTMLElements} from 'svelte/elements';
|
|
6
|
-
import {EMPTY_OBJECT} from '@fuzdev/fuz_util/object.ts';
|
|
7
|
-
import type {Attachment} from 'svelte/attachments';
|
|
8
|
-
|
|
9
|
-
import {Dimensions} from './dimensions.svelte.ts';
|
|
10
|
-
import {create_context} from './context_helpers.ts';
|
|
11
|
-
import {url_to_root_relative} from './library_helpers.ts';
|
|
12
|
-
import {icon_copy} from './icons.ts';
|
|
13
|
-
import type {SvgData} from './svg.ts';
|
|
1
|
+
import { onDestroy, type Snippet } from 'svelte';
|
|
2
|
+
import type { Result } from '@fuzdev/fuz_util/result.ts';
|
|
3
|
+
import { is_promise } from '@fuzdev/fuz_util/async.ts';
|
|
4
|
+
import { BROWSER, DEV } from 'esm-env';
|
|
5
|
+
import type { SvelteHTMLElements } from 'svelte/elements';
|
|
6
|
+
import { EMPTY_OBJECT } from '@fuzdev/fuz_util/object.ts';
|
|
7
|
+
import type { Attachment } from 'svelte/attachments';
|
|
8
|
+
|
|
9
|
+
import { Dimensions } from './dimensions.svelte.ts';
|
|
10
|
+
import { create_context } from './context_helpers.ts';
|
|
11
|
+
import { url_to_root_relative } from './library_helpers.ts';
|
|
12
|
+
import { icon_copy } from './icons.ts';
|
|
13
|
+
import type { SvgData } from './svg.ts';
|
|
14
14
|
|
|
15
15
|
export const contextmenu_context = create_context<() => ContextmenuState>();
|
|
16
16
|
|
|
@@ -21,14 +21,12 @@ export const contextmenu_dimensions_context = create_context(() => new Dimension
|
|
|
21
21
|
export type ContextmenuParams =
|
|
22
22
|
| Snippet
|
|
23
23
|
// TODO maybe this should be generic?
|
|
24
|
-
| {snippet: 'link'; props: {href: string; icon?: string}}
|
|
25
|
-
| {snippet: 'text'; props: {content: string; icon: SvgData | string; run: ContextmenuRun}}
|
|
26
|
-
| {snippet: 'separator'; props: SvelteHTMLElements['li']};
|
|
24
|
+
| { snippet: 'link'; props: { href: string; icon?: string } }
|
|
25
|
+
| { snippet: 'text'; props: { content: string; icon: SvgData | string; run: ContextmenuRun } }
|
|
26
|
+
| { snippet: 'separator'; props: SvelteHTMLElements['li'] };
|
|
27
27
|
|
|
28
28
|
export type ContextmenuActivateResult =
|
|
29
|
-
|
|
|
30
|
-
| undefined
|
|
31
|
-
| Result<{close?: boolean}, {message?: string}>;
|
|
29
|
+
void | undefined | Result<{ close?: boolean }, { message?: string }>;
|
|
32
30
|
|
|
33
31
|
export type ItemState = SubmenuState | EntryState;
|
|
34
32
|
|
|
@@ -47,7 +45,7 @@ export class EntryState {
|
|
|
47
45
|
constructor(
|
|
48
46
|
menu: SubmenuState | RootMenuState,
|
|
49
47
|
run: () => ContextmenuRun,
|
|
50
|
-
disabled: () => boolean = () => false
|
|
48
|
+
disabled: () => boolean = () => false
|
|
51
49
|
) {
|
|
52
50
|
this.menu = menu;
|
|
53
51
|
this.run = run;
|
|
@@ -124,7 +122,7 @@ export type ContextmenuRun = () => ContextmenuActivateResult | Promise<Contextme
|
|
|
124
122
|
|
|
125
123
|
/** Extracts a string `message` property from a thrown value or failed result, if present. */
|
|
126
124
|
const to_error_message = (value: unknown): string | undefined => {
|
|
127
|
-
const message = (value as {message?: unknown} | null | undefined)?.message;
|
|
125
|
+
const message = (value as { message?: unknown } | null | undefined)?.message;
|
|
128
126
|
return typeof message === 'string' ? message : undefined;
|
|
129
127
|
};
|
|
130
128
|
|
|
@@ -193,7 +191,7 @@ export class ContextmenuState {
|
|
|
193
191
|
});
|
|
194
192
|
|
|
195
193
|
constructor(options: ContextmenuStateOptions = EMPTY_OBJECT) {
|
|
196
|
-
const {layout} = options;
|
|
194
|
+
const { layout } = options;
|
|
197
195
|
|
|
198
196
|
this.has_custom_layout = !!layout;
|
|
199
197
|
this.layout = layout ?? new Dimensions();
|
|
@@ -203,7 +201,7 @@ export class ContextmenuState {
|
|
|
203
201
|
params: Array<ContextmenuParams>,
|
|
204
202
|
x: number,
|
|
205
203
|
y: number,
|
|
206
|
-
target?: HTMLElement | SVGElement
|
|
204
|
+
target?: HTMLElement | SVGElement
|
|
207
205
|
): void {
|
|
208
206
|
this.#clear_selections();
|
|
209
207
|
this.opened = true;
|
|
@@ -311,7 +309,7 @@ export class ContextmenuState {
|
|
|
311
309
|
(err) => {
|
|
312
310
|
if (promise !== item.promise) return;
|
|
313
311
|
this.#handle_error(item, to_error_message(err));
|
|
314
|
-
}
|
|
312
|
+
}
|
|
315
313
|
)
|
|
316
314
|
.finally(() => {
|
|
317
315
|
if (promise !== item.promise) return;
|
|
@@ -411,7 +409,7 @@ export class ContextmenuState {
|
|
|
411
409
|
}
|
|
412
410
|
|
|
413
411
|
select_last(): void {
|
|
414
|
-
const {items} = this.selections.at(-1)?.menu ?? this.root_menu;
|
|
412
|
+
const { items } = this.selections.at(-1)?.menu ?? this.root_menu;
|
|
415
413
|
if (!items.length) return;
|
|
416
414
|
this.select(items.at(-1)!);
|
|
417
415
|
}
|
|
@@ -462,7 +460,7 @@ const contextmenu_params_by_element: WeakMap<
|
|
|
462
460
|
*/
|
|
463
461
|
export const contextmenu_attachment =
|
|
464
462
|
(
|
|
465
|
-
params: ContextmenuParams | Array<ContextmenuParams> | null | undefined
|
|
463
|
+
params: ContextmenuParams | Array<ContextmenuParams> | null | undefined
|
|
466
464
|
): Attachment<HTMLElement | SVGElement> =>
|
|
467
465
|
(el): undefined | (() => void) => {
|
|
468
466
|
if (params == null) return;
|
|
@@ -500,13 +498,13 @@ export const contextmenu_open = (
|
|
|
500
498
|
x: number,
|
|
501
499
|
y: number,
|
|
502
500
|
contextmenu: ContextmenuState,
|
|
503
|
-
options?: ContextmenuOpenOptions
|
|
501
|
+
options?: ContextmenuOpenOptions
|
|
504
502
|
): boolean => {
|
|
505
503
|
const {
|
|
506
504
|
link_enabled = true,
|
|
507
505
|
text_enabled = true,
|
|
508
506
|
separator_enabled = true,
|
|
509
|
-
vibrate = true
|
|
507
|
+
vibrate = true
|
|
510
508
|
} = options ?? EMPTY_OBJECT;
|
|
511
509
|
|
|
512
510
|
const params = contextmenu_query_params(target)?.filter(
|
|
@@ -514,7 +512,7 @@ export const contextmenu_open = (
|
|
|
514
512
|
typeof p === 'function' ||
|
|
515
513
|
((p.snippet !== 'link' || link_enabled) &&
|
|
516
514
|
(p.snippet !== 'text' || text_enabled) &&
|
|
517
|
-
(p.snippet !== 'separator' || separator_enabled))
|
|
515
|
+
(p.snippet !== 'separator' || separator_enabled))
|
|
518
516
|
);
|
|
519
517
|
|
|
520
518
|
// No-op if empty
|
|
@@ -534,7 +532,7 @@ export const contextmenu_open = (
|
|
|
534
532
|
};
|
|
535
533
|
|
|
536
534
|
const contextmenu_query_params = (
|
|
537
|
-
target: HTMLElement | SVGElement
|
|
535
|
+
target: HTMLElement | SVGElement
|
|
538
536
|
): null | Array<ContextmenuParams> => {
|
|
539
537
|
let params: null | Array<ContextmenuParams> = null;
|
|
540
538
|
// crawl DOM for contextmenu entries
|
|
@@ -555,7 +553,7 @@ const contextmenu_query_params = (
|
|
|
555
553
|
(params ??= []).push({
|
|
556
554
|
snippet: 'link',
|
|
557
555
|
// anchor elements have the full url, but we want the slash-prefixed/absolute/root-relative version
|
|
558
|
-
props: {href: url_to_root_relative((el as HTMLAnchorElement).href)}
|
|
556
|
+
props: { href: url_to_root_relative((el as HTMLAnchorElement).href) }
|
|
559
557
|
});
|
|
560
558
|
}
|
|
561
559
|
el = el.parentElement;
|
|
@@ -571,8 +569,8 @@ const contextmenu_query_params = (
|
|
|
571
569
|
icon: icon_copy,
|
|
572
570
|
run: async () => {
|
|
573
571
|
await navigator.clipboard.writeText(text);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
576
574
|
});
|
|
577
575
|
}
|
|
578
576
|
}
|
|
@@ -603,7 +601,7 @@ export const contextmenu_check_global_root = (get_scoped: () => boolean): void =
|
|
|
603
601
|
console.error(
|
|
604
602
|
`Detected multiple non-scoped contextmenu roots (${non_scoped_roots.size} mounted). ` +
|
|
605
603
|
'Only one global contextmenu root should be active at a time. ' +
|
|
606
|
-
'Are you missing a `scoped` attribute?'
|
|
604
|
+
'Are you missing a `scoped` attribute?'
|
|
607
605
|
);
|
|
608
606
|
}
|
|
609
607
|
}
|
package/src/lib/csp.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {Defined} from '@fuzdev/fuz_util/types.ts';
|
|
1
|
+
import type { Defined } from '@fuzdev/fuz_util/types.ts';
|
|
2
2
|
|
|
3
3
|
// TODO schemas, but I may be moving to ArkType from Zod if precompilation looks good
|
|
4
4
|
|
|
@@ -87,12 +87,12 @@ export interface CreateCspDirectivesOptions {
|
|
|
87
87
|
* Things like rendering to a string are out of scope and left to SvelteKit.
|
|
88
88
|
*/
|
|
89
89
|
export const create_csp_directives = (options: CreateCspDirectivesOptions = {}): CspDirectives => {
|
|
90
|
-
const {replace_defaults = csp_directive_value_defaults, extend, overrides} = options;
|
|
90
|
+
const { replace_defaults = csp_directive_value_defaults, extend, overrides } = options;
|
|
91
91
|
|
|
92
92
|
if (replace_defaults === null) {
|
|
93
93
|
throw new Error(
|
|
94
94
|
`Invalid value 'null' for options.replace_defaults. ` +
|
|
95
|
-
`Omit the option to use library defaults, or pass {} to start with no directives
|
|
95
|
+
`Omit the option to use library defaults, or pass {} to start with no directives.`
|
|
96
96
|
);
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -114,7 +114,7 @@ export const create_csp_directives = (options: CreateCspDirectivesOptions = {}):
|
|
|
114
114
|
if (value === null) {
|
|
115
115
|
throw new Error(
|
|
116
116
|
`Invalid value 'null' for directive '${directive}' in options.replace_defaults. ` +
|
|
117
|
-
`Omit the key instead, or use \`overrides: { '${directive}': null }\` to remove
|
|
117
|
+
`Omit the key instead, or use \`overrides: { '${directive}': null }\` to remove.`
|
|
118
118
|
);
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -135,14 +135,12 @@ export const create_csp_directives = (options: CreateCspDirectivesOptions = {}):
|
|
|
135
135
|
throw new Error(
|
|
136
136
|
`Cannot extend directive '${directive}' with null. ` +
|
|
137
137
|
`extend can only append sources — to remove a directive from the output, ` +
|
|
138
|
-
`use \`overrides: { '${directive}': null }
|
|
138
|
+
`use \`overrides: { '${directive}': null }\`.`
|
|
139
139
|
);
|
|
140
140
|
}
|
|
141
141
|
if (!Array.isArray(value)) {
|
|
142
142
|
throw new Error(
|
|
143
|
-
`Cannot extend directive '${directive}': value must be an array of sources, got ${
|
|
144
|
-
typeof value
|
|
145
|
-
}.`,
|
|
143
|
+
`Cannot extend directive '${directive}': value must be an array of sources, got ${typeof value}.`
|
|
146
144
|
);
|
|
147
145
|
}
|
|
148
146
|
if (!value.length) return;
|
|
@@ -153,7 +151,7 @@ export const create_csp_directives = (options: CreateCspDirectivesOptions = {}):
|
|
|
153
151
|
`The pipeline runs replace_defaults → extend → overrides, so an \`overrides\` ` +
|
|
154
152
|
`entry for '${directive}' cannot rescue this — extend sees the ['none'] starting ` +
|
|
155
153
|
`value first. Opt in via \`replace_defaults: { '${directive}': [...] }\` or move ` +
|
|
156
|
-
`the sources into \`overrides: { '${directive}': [...] }
|
|
154
|
+
`the sources into \`overrides: { '${directive}': [...] }\`.`
|
|
157
155
|
);
|
|
158
156
|
}
|
|
159
157
|
if (current === undefined) {
|
|
@@ -184,13 +182,13 @@ export const create_csp_directives = (options: CreateCspDirectivesOptions = {}):
|
|
|
184
182
|
if (!Array.isArray(value)) {
|
|
185
183
|
throw new Error(
|
|
186
184
|
`Directive '${key}' has an invalid value: expected an array of sources or a boolean, ` +
|
|
187
|
-
`got ${value === null ? 'null' : typeof value}
|
|
185
|
+
`got ${value === null ? 'null' : typeof value}.`
|
|
188
186
|
);
|
|
189
187
|
}
|
|
190
188
|
if (value.length === 0) {
|
|
191
189
|
throw new Error(
|
|
192
190
|
`Directive '${key}' has an empty array. ` +
|
|
193
|
-
`Use ['none'] to forbid all sources, or omit the directive entirely
|
|
191
|
+
`Use ['none'] to forbid all sources, or omit the directive entirely.`
|
|
194
192
|
);
|
|
195
193
|
}
|
|
196
194
|
// Element-level type check — the `CspSource` template-string type gates this at the
|
|
@@ -202,14 +200,14 @@ export const create_csp_directives = (options: CreateCspDirectivesOptions = {}):
|
|
|
202
200
|
throw new Error(
|
|
203
201
|
`Directive '${key}' has a non-string source at index ${i}: got ${
|
|
204
202
|
v === null ? 'null' : typeof v
|
|
205
|
-
}
|
|
203
|
+
}.`
|
|
206
204
|
);
|
|
207
205
|
}
|
|
208
206
|
}
|
|
209
207
|
if (value.length > 1 && (value as Array<unknown>).includes('none')) {
|
|
210
208
|
throw new Error(
|
|
211
209
|
`Directive '${key}' has 'none' alongside other tokens (${value.join(', ')}). ` +
|
|
212
|
-
`'none' must appear alone in CSP
|
|
210
|
+
`'none' must appear alone in CSP.`
|
|
213
211
|
);
|
|
214
212
|
}
|
|
215
213
|
}
|
|
@@ -241,7 +239,7 @@ const is_none = (value: unknown): boolean =>
|
|
|
241
239
|
const for_each_directive = <V>(
|
|
242
240
|
source: Record<string, V>,
|
|
243
241
|
source_label: 'replace_defaults' | 'extend' | 'overrides',
|
|
244
|
-
fn: (directive: CspDirective, value: V) => void
|
|
242
|
+
fn: (directive: CspDirective, value: V) => void
|
|
245
243
|
): void => {
|
|
246
244
|
if (source === null || typeof source !== 'object') {
|
|
247
245
|
const got = source === null ? 'null' : typeof source;
|
|
@@ -294,7 +292,7 @@ export const csp_directive_value_defaults: Partial<{
|
|
|
294
292
|
'worker-src': ['self', 'blob:', 'wasm-unsafe-eval'], // Web workers
|
|
295
293
|
'object-src': ['none'], // Block plugins (Flash, Java, etc.)
|
|
296
294
|
'base-uri': ['none'], // Prevent base tag hijacking
|
|
297
|
-
'upgrade-insecure-requests': true
|
|
295
|
+
'upgrade-insecure-requests': true // Upgrade http to https
|
|
298
296
|
};
|
|
299
297
|
|
|
300
298
|
export interface CspDirectiveSpec {
|
|
@@ -328,128 +326,128 @@ export const csp_directive_specs: Array<CspDirectiveSpec> = [
|
|
|
328
326
|
'child-src',
|
|
329
327
|
'connect-src',
|
|
330
328
|
'worker-src',
|
|
331
|
-
'object-src'
|
|
332
|
-
]
|
|
329
|
+
'object-src'
|
|
330
|
+
]
|
|
333
331
|
},
|
|
334
332
|
{
|
|
335
333
|
name: 'script-src',
|
|
336
334
|
fallback: ['default-src'],
|
|
337
|
-
fallback_of: ['script-src-elem', 'script-src-attr', 'worker-src']
|
|
335
|
+
fallback_of: ['script-src-elem', 'script-src-attr', 'worker-src']
|
|
338
336
|
},
|
|
339
337
|
{
|
|
340
338
|
name: 'script-src-elem',
|
|
341
339
|
fallback: ['script-src', 'default-src'],
|
|
342
|
-
fallback_of: null
|
|
340
|
+
fallback_of: null
|
|
343
341
|
},
|
|
344
342
|
{
|
|
345
343
|
name: 'script-src-attr',
|
|
346
344
|
fallback: ['script-src', 'default-src'],
|
|
347
|
-
fallback_of: null
|
|
345
|
+
fallback_of: null
|
|
348
346
|
},
|
|
349
347
|
{
|
|
350
348
|
name: 'style-src',
|
|
351
349
|
fallback: ['default-src'],
|
|
352
|
-
fallback_of: ['style-src-elem', 'style-src-attr']
|
|
350
|
+
fallback_of: ['style-src-elem', 'style-src-attr']
|
|
353
351
|
},
|
|
354
352
|
{
|
|
355
353
|
name: 'style-src-elem',
|
|
356
354
|
fallback: ['style-src', 'default-src'],
|
|
357
|
-
fallback_of: null
|
|
355
|
+
fallback_of: null
|
|
358
356
|
},
|
|
359
357
|
{
|
|
360
358
|
name: 'style-src-attr',
|
|
361
359
|
fallback: ['style-src', 'default-src'],
|
|
362
|
-
fallback_of: null
|
|
360
|
+
fallback_of: null
|
|
363
361
|
},
|
|
364
362
|
{
|
|
365
363
|
name: 'img-src',
|
|
366
364
|
fallback: ['default-src'],
|
|
367
|
-
fallback_of: null
|
|
365
|
+
fallback_of: null
|
|
368
366
|
},
|
|
369
367
|
{
|
|
370
368
|
name: 'media-src',
|
|
371
369
|
fallback: ['default-src'],
|
|
372
|
-
fallback_of: null
|
|
370
|
+
fallback_of: null
|
|
373
371
|
},
|
|
374
372
|
{
|
|
375
373
|
name: 'font-src',
|
|
376
374
|
fallback: ['default-src'],
|
|
377
|
-
fallback_of: null
|
|
375
|
+
fallback_of: null
|
|
378
376
|
},
|
|
379
377
|
{
|
|
380
378
|
name: 'manifest-src',
|
|
381
379
|
fallback: ['default-src'],
|
|
382
|
-
fallback_of: null
|
|
380
|
+
fallback_of: null
|
|
383
381
|
},
|
|
384
382
|
{
|
|
385
383
|
name: 'child-src',
|
|
386
384
|
fallback: ['default-src'],
|
|
387
|
-
fallback_of: ['frame-src', 'worker-src']
|
|
385
|
+
fallback_of: ['frame-src', 'worker-src']
|
|
388
386
|
},
|
|
389
387
|
{
|
|
390
388
|
name: 'connect-src',
|
|
391
389
|
fallback: ['default-src'],
|
|
392
|
-
fallback_of: null
|
|
390
|
+
fallback_of: null
|
|
393
391
|
},
|
|
394
392
|
{
|
|
395
393
|
name: 'frame-src',
|
|
396
394
|
fallback: ['child-src'],
|
|
397
|
-
fallback_of: null
|
|
395
|
+
fallback_of: null
|
|
398
396
|
},
|
|
399
397
|
{
|
|
400
398
|
name: 'frame-ancestors',
|
|
401
399
|
fallback: null,
|
|
402
|
-
fallback_of: null
|
|
400
|
+
fallback_of: null
|
|
403
401
|
},
|
|
404
402
|
{
|
|
405
403
|
name: 'form-action',
|
|
406
404
|
fallback: null,
|
|
407
|
-
fallback_of: null
|
|
405
|
+
fallback_of: null
|
|
408
406
|
},
|
|
409
407
|
{
|
|
410
408
|
name: 'worker-src',
|
|
411
409
|
fallback: ['child-src', 'script-src', 'default-src'],
|
|
412
|
-
fallback_of: null
|
|
410
|
+
fallback_of: null
|
|
413
411
|
},
|
|
414
412
|
{
|
|
415
413
|
name: 'object-src',
|
|
416
414
|
fallback: ['default-src'],
|
|
417
|
-
fallback_of: null
|
|
415
|
+
fallback_of: null
|
|
418
416
|
},
|
|
419
417
|
{
|
|
420
418
|
name: 'base-uri',
|
|
421
419
|
fallback: null,
|
|
422
|
-
fallback_of: null
|
|
420
|
+
fallback_of: null
|
|
423
421
|
},
|
|
424
422
|
{
|
|
425
423
|
name: 'upgrade-insecure-requests',
|
|
426
424
|
fallback: null,
|
|
427
|
-
fallback_of: null
|
|
425
|
+
fallback_of: null
|
|
428
426
|
},
|
|
429
427
|
{
|
|
430
428
|
name: 'report-to',
|
|
431
429
|
fallback: null,
|
|
432
|
-
fallback_of: null
|
|
430
|
+
fallback_of: null
|
|
433
431
|
},
|
|
434
432
|
{
|
|
435
433
|
name: 'require-trusted-types-for',
|
|
436
434
|
fallback: null,
|
|
437
|
-
fallback_of: null
|
|
435
|
+
fallback_of: null
|
|
438
436
|
},
|
|
439
437
|
{
|
|
440
438
|
name: 'trusted-types',
|
|
441
439
|
fallback: null,
|
|
442
|
-
fallback_of: null
|
|
440
|
+
fallback_of: null
|
|
443
441
|
},
|
|
444
442
|
{
|
|
445
443
|
name: 'sandbox',
|
|
446
444
|
fallback: null,
|
|
447
|
-
fallback_of: null
|
|
448
|
-
}
|
|
445
|
+
fallback_of: null
|
|
446
|
+
}
|
|
449
447
|
];
|
|
450
448
|
|
|
451
449
|
export const csp_directive_spec_by_name: Map<CspDirective, CspDirectiveSpec> = new Map(
|
|
452
|
-
csp_directive_specs.map((s) => [s.name, s])
|
|
450
|
+
csp_directive_specs.map((s) => [s.name, s])
|
|
453
451
|
);
|
|
454
452
|
|
|
455
453
|
// CSP types from SvelteKit, adapted with changes from @sveltejs/kit/src/types/private.d.ts
|
|
@@ -482,12 +480,7 @@ export const csp_directive_spec_by_name: Map<CspDirective, CspDirectiveSpec> = n
|
|
|
482
480
|
// SOFTWARE.
|
|
483
481
|
export type CspActionSource = 'strict-dynamic' | 'report-sample';
|
|
484
482
|
export type CspBaseSource =
|
|
485
|
-
| '
|
|
486
|
-
| 'unsafe-eval'
|
|
487
|
-
| 'unsafe-hashes'
|
|
488
|
-
| 'unsafe-inline'
|
|
489
|
-
| 'wasm-unsafe-eval'
|
|
490
|
-
| 'none';
|
|
483
|
+
'self' | 'unsafe-eval' | 'unsafe-hashes' | 'unsafe-inline' | 'wasm-unsafe-eval' | 'none';
|
|
491
484
|
export type CspCryptoSource = `${'nonce' | 'sha256' | 'sha384' | 'sha512'}-${string}`;
|
|
492
485
|
export type CspFrameSource = CspHostSource | CspSchemeSource | 'self' | 'none';
|
|
493
486
|
export type CspHostNameScheme = `${string}.${string}` | 'localhost';
|
|
@@ -495,12 +488,7 @@ export type CspHostSource = `${CspHostProtocolSchemes}${CspHostNameScheme}${CspP
|
|
|
495
488
|
export type CspHostProtocolSchemes = `${string}://` | '';
|
|
496
489
|
export type CspPortScheme = `:${number}` | '' | ':*';
|
|
497
490
|
export type CspSchemeSource =
|
|
498
|
-
| '
|
|
499
|
-
| 'https:'
|
|
500
|
-
| 'data:'
|
|
501
|
-
| 'mediastream:'
|
|
502
|
-
| 'blob:'
|
|
503
|
-
| 'filesystem:';
|
|
491
|
+
'http:' | 'https:' | 'data:' | 'mediastream:' | 'blob:' | 'filesystem:';
|
|
504
492
|
export type CspSource = CspHostSource | CspSchemeSource | CspCryptoSource | CspBaseSource;
|
|
505
493
|
export type CspSources = Array<CspSource>;
|
|
506
494
|
|
package/src/lib/csp_of_fuzdev.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {CspDirectives} from './csp.ts';
|
|
1
|
+
import type { CspDirectives } from './csp.ts';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Per-directive sources that allow full interop between fuzdev/sister sites
|
|
@@ -19,7 +19,7 @@ export const csp_directives_of_fuzdev: Partial<CspDirectives> = {
|
|
|
19
19
|
'font-src': ['https://*.fuz.dev/', 'https://*.zzz.software/'],
|
|
20
20
|
'connect-src': ['https://*.fuz.dev/', 'https://*.zzz.software/'],
|
|
21
21
|
'frame-src': ['https://*.fuz.dev/', 'https://*.zzz.software/'],
|
|
22
|
-
'frame-ancestors': ['https://*.fuz.dev/', 'https://*.zzz.software/']
|
|
22
|
+
'frame-ancestors': ['https://*.fuz.dev/', 'https://*.zzz.software/']
|
|
23
23
|
// `child-src` is intentionally omitted — it defaults to `['none']`, and `extend` cannot
|
|
24
24
|
// append to a `'none'`-valued directive. Including it here would break the common
|
|
25
25
|
// `create_csp_directives({extend: [csp_directives_of_fuzdev]})` call. `frame-src` is its
|