@fuzdev/fuz_ui 0.191.4 → 0.193.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/ApiIndex.svelte +3 -3
  2. package/dist/ApiModule.svelte +2 -2
  3. package/dist/ApiModulesList.svelte +3 -3
  4. package/dist/ColorSchemeInput.svelte +6 -6
  5. package/dist/ContextmenuLinkEntry.svelte +1 -1
  6. package/dist/ContextmenuRoot.svelte +10 -10
  7. package/dist/ContextmenuRootForSafariCompatibility.svelte +19 -19
  8. package/dist/ContextmenuSeparator.svelte +3 -3
  9. package/dist/ContextmenuSubmenu.svelte +3 -3
  10. package/dist/CopyToClipboard.svelte +3 -3
  11. package/dist/DeclarationLink.svelte +1 -1
  12. package/dist/Dialog.svelte +16 -16
  13. package/dist/Docs.svelte +12 -12
  14. package/dist/DocsFooter.svelte +2 -2
  15. package/dist/DocsList.svelte +7 -7
  16. package/dist/DocsMenu.svelte +4 -4
  17. package/dist/DocsMenu.svelte.d.ts.map +1 -1
  18. package/dist/DocsPageLinks.svelte +4 -4
  19. package/dist/DocsPrimaryNav.svelte +2 -2
  20. package/dist/DocsSecondaryNav.svelte +4 -4
  21. package/dist/DocsTertiaryNav.svelte +13 -13
  22. package/dist/DocsTertiaryNav.svelte.d.ts +1 -1
  23. package/dist/GithubLink.svelte +1 -1
  24. package/dist/Hashlink.svelte +2 -2
  25. package/dist/HueInput.svelte +5 -5
  26. package/dist/LibraryDetail.svelte +8 -8
  27. package/dist/LibrarySummary.svelte +4 -4
  28. package/dist/MdnLink.svelte +1 -1
  29. package/dist/ModuleLink.svelte +1 -1
  30. package/dist/PasteFromClipboard.svelte +1 -1
  31. package/dist/PendingAnimation.svelte +2 -2
  32. package/dist/PendingButton.svelte +2 -2
  33. package/dist/ProjectLinks.svelte +4 -4
  34. package/dist/Teleport.svelte +2 -2
  35. package/dist/ThemeInput.svelte +5 -5
  36. package/dist/TomeContent.svelte +3 -3
  37. package/dist/TomeHeader.svelte +15 -14
  38. package/dist/TomeHeader.svelte.d.ts.map +1 -1
  39. package/dist/TomeLink.svelte +13 -6
  40. package/dist/TomeLink.svelte.d.ts +1 -1
  41. package/dist/TomeLink.svelte.d.ts.map +1 -1
  42. package/dist/TomeSection.svelte +1 -1
  43. package/dist/TomeSectionHeader.svelte +3 -3
  44. package/dist/api_search.svelte.js +2 -2
  45. package/dist/contextmenu_state.svelte.d.ts.map +1 -1
  46. package/dist/contextmenu_state.svelte.js +11 -10
  47. package/dist/csp.d.ts +81 -90
  48. package/dist/csp.d.ts.map +1 -1
  49. package/dist/csp.js +145 -163
  50. package/dist/csp_of_fuzdev.d.ts +13 -3
  51. package/dist/csp_of_fuzdev.d.ts.map +1 -1
  52. package/dist/csp_of_fuzdev.js +23 -7
  53. package/dist/dimensions.svelte.d.ts.map +1 -1
  54. package/dist/dimensions.svelte.js +2 -2
  55. package/dist/library.svelte.d.ts +1 -1
  56. package/dist/library_generate.js +1 -1
  57. package/dist/style_variable_helpers.svelte.d.ts.map +1 -1
  58. package/dist/style_variable_helpers.svelte.js +1 -1
  59. package/dist/theme_state.svelte.d.ts.map +1 -1
  60. package/dist/theme_state.svelte.js +2 -2
  61. package/dist/tome.d.ts +8 -3
  62. package/dist/tome.d.ts.map +1 -1
  63. package/dist/tome.js +24 -8
  64. package/dist/tsdoc_helpers.d.ts +9 -0
  65. package/dist/tsdoc_helpers.d.ts.map +1 -1
  66. package/dist/tsdoc_helpers.js +15 -5
  67. package/package.json +5 -5
  68. package/src/lib/api_search.svelte.ts +2 -2
  69. package/src/lib/contextmenu_state.svelte.ts +11 -10
  70. package/src/lib/csp.ts +224 -258
  71. package/src/lib/csp_of_fuzdev.ts +24 -8
  72. package/src/lib/dimensions.svelte.ts +2 -2
  73. package/src/lib/library_generate.ts +1 -1
  74. package/src/lib/style_variable_helpers.svelte.ts +1 -1
  75. package/src/lib/theme_state.svelte.ts +2 -2
  76. package/src/lib/tome.ts +25 -8
  77. package/src/lib/tsdoc_helpers.ts +18 -7
package/dist/csp.js CHANGED
@@ -1,155 +1,175 @@
1
1
  /**
2
- * This is designed for compatibility with SvelteKit
3
- * and maps to the `KitConfig` `directives` option.
4
- * The goal is to provide an ergonomic, modern, and safe API
5
- * for Content Security Policy (CSP) creation
6
- * that's simple to write and audit, and isn't error-prone.
2
+ * Builds a CSP directives map for use with SvelteKit's `kit.csp.directives` option.
7
3
  *
8
- * Things like validation and rendering to a string
9
- * are out of scope and left to SvelteKit.
4
+ * Restrictive by default; opt into specific permissions via `extend` (append) or
5
+ * `overrides` (replace). Designed to read as an audit log: every user-added source
6
+ * is named at exactly one site in the source code. Library defaults are inherited
7
+ * unless you opt out via `replace_defaults`.
8
+ *
9
+ * Validation:
10
+ * - Unknown directive keys throw.
11
+ * - Extending a `['none']` directive throws (use `replace_defaults`/`overrides` to opt in).
12
+ * - `null` for `replace_defaults` (top-level or per-key) throws — omit the option for library
13
+ * defaults, pass `{}` to start blank, or use `overrides` to remove a specific directive.
14
+ * - `null` per-key in `extend` throws (use `overrides` for removal).
15
+ * - `undefined` per-key is treated as omitted in all three stages.
16
+ * - Non-object entries in `extend` (`null`, `undefined`, primitives) throw with a friendly error.
17
+ * - Output is validated to ensure `'none'` never appears alongside other tokens,
18
+ * that no directive ends up with an empty array (use `['none']` to forbid all),
19
+ * and that every source array contains only strings.
20
+ *
21
+ * Things like rendering to a string are out of scope and left to SvelteKit.
10
22
  */
11
- export function create_csp_directives(options = {}) {
12
- const { directives: directives_option, trusted_sources, value_defaults_base = csp_directive_value_defaults, value_defaults: value_defaults_option, required_trust_defaults_base = csp_directive_required_trust_defaults, required_trust_defaults: required_trust_defaults_option, } = options;
23
+ export const create_csp_directives = (options = {}) => {
24
+ const { replace_defaults = csp_directive_value_defaults, extend, overrides } = options;
25
+ if (replace_defaults === null) {
26
+ throw new Error(`Invalid value 'null' for options.replace_defaults. ` +
27
+ `Omit the option to use library defaults, or pass {} to start with no directives.`);
28
+ }
13
29
  const directives = {};
14
- // Shallowly merge any provided defaults with the base defaults
15
- const value_defaults = { ...value_defaults_base, ...value_defaults_option };
16
- // Merge required trust defaults with the base
17
- const required_trust_defaults = {
18
- ...required_trust_defaults_base,
19
- ...required_trust_defaults_option,
30
+ // `Object.entries` widens to `[string, unknown]` and TS can't re-narrow per-key, so
31
+ // writes via the validated `directive` need a single trusted-bridge cast — kept inside
32
+ // this helper so the call sites stay free of type assertions. Clones arrays so callers
33
+ // don't have to worry about user-supplied arrays leaking into the output.
34
+ const assign = (directive, value) => {
35
+ directives[directive] = Array.isArray(value)
36
+ ? [...value]
37
+ : value;
20
38
  };
21
- // Apply defaults from directive specs
22
- for (const spec of csp_directive_specs) {
23
- const default_value = value_defaults[spec.name];
24
- if (default_value == null)
25
- continue; // omit null and undefined
26
- directives[spec.name] = Array.isArray(default_value)
27
- ? [...default_value]
28
- : default_value;
29
- }
30
- // Get trust requirements (with overrides applied)
31
- const trust_requirements = new Map();
32
- for (const spec of csp_directive_specs) {
33
- const required_trust = required_trust_defaults[spec.name];
34
- if (required_trust == null)
35
- continue; // omit null and undefined
36
- trust_requirements.set(spec.name, required_trust);
37
- }
38
- // Validate trusted_sources directives
39
- if (trusted_sources?.length) {
40
- for (const spec of trusted_sources) {
41
- if (spec.directives) {
42
- for (const directive of spec.directives) {
43
- if (parse_csp_directive(directive) === null) {
44
- throw new Error(`Invalid directive in trusted_sources: ${directive}`);
45
- }
39
+ // Stage 1: starting state from `replace_defaults`.
40
+ // `{}` starts blank — every directive must come from `extend`/`overrides`.
41
+ for_each_directive(replace_defaults, 'replace_defaults', (directive, value) => {
42
+ if (value === null) {
43
+ throw new Error(`Invalid value 'null' for directive '${directive}' in options.replace_defaults. ` +
44
+ `Omit the key instead, or use \`overrides: { '${directive}': null }\` to remove.`);
45
+ }
46
+ if (value === undefined)
47
+ return;
48
+ assign(directive, value);
49
+ });
50
+ // Stage 2: append sources per layer in `extend`.
51
+ if (extend?.length) {
52
+ for (const layer of extend) {
53
+ for_each_directive(layer, 'extend', (directive, value) => {
54
+ // `undefined` is treated as omitted, matching `replace_defaults`/`overrides`.
55
+ // Lets callers write `{'connect-src': cond ? [API] : undefined}` naturally.
56
+ if (value === undefined)
57
+ return;
58
+ // `null` is meaningful enough to deserve its own error — users reaching for null
59
+ // in extend almost always want removal, which lives on `overrides`.
60
+ if (value === null) {
61
+ throw new Error(`Cannot extend directive '${directive}' with null. ` +
62
+ `extend can only append sources — to remove a directive from the output, ` +
63
+ `use \`overrides: { '${directive}': null }\`.`);
46
64
  }
47
- }
65
+ if (!Array.isArray(value)) {
66
+ throw new Error(`Cannot extend directive '${directive}': value must be an array of sources, got ${typeof value}.`);
67
+ }
68
+ if (!value.length)
69
+ return;
70
+ const current = directives[directive];
71
+ if (is_none(current)) {
72
+ throw new Error(`Cannot extend directive '${directive}' while its current value is ['none']. ` +
73
+ `The pipeline runs replace_defaults → extend → overrides, so an \`overrides\` ` +
74
+ `entry for '${directive}' cannot rescue this — extend sees the ['none'] starting ` +
75
+ `value first. Opt in via \`replace_defaults: { '${directive}': [...] }\` or move ` +
76
+ `the sources into \`overrides: { '${directive}': [...] }\`.`);
77
+ }
78
+ if (current === undefined) {
79
+ assign(directive, [...new Set(value)]);
80
+ }
81
+ else if (Array.isArray(current)) {
82
+ assign(directive, [...new Set([...current, ...value])]);
83
+ }
84
+ else {
85
+ throw new Error(`Cannot extend directive '${directive}': it has a non-array value.`);
86
+ }
87
+ });
48
88
  }
49
89
  }
50
- // Apply trusted sources to directives
51
- if (trusted_sources?.length) {
52
- for (const [key, value] of Object.entries(directives)) {
53
- const directive = parse_csp_directive(key);
54
- if (directive === null) {
55
- throw new Error(`Invalid directive in options.directives: ${key}`);
56
- }
57
- // Skip if directive is ['none'] or not an array
58
- if (is_none_directive(value) || !Array.isArray(value)) {
59
- continue;
90
+ // Stage 3: final-pass `overrides` — replace value or remove key.
91
+ if (overrides) {
92
+ for_each_directive(overrides, 'overrides', (directive, value) => {
93
+ if (value === null) {
94
+ delete directives[directive]; // eslint-disable-line @typescript-eslint/no-dynamic-delete
60
95
  }
61
- // Get required trust for this directive
62
- const required_trust = trust_requirements.get(directive);
63
- if (required_trust == null)
64
- continue;
65
- // Add matching sources - separate the filtering into trust-based and directive-based inclusion
66
- const sources_to_add = trusted_sources
67
- .filter((spec) => {
68
- // Check for explicit inclusion in directives list
69
- const explicitly_included = spec.directives?.includes(directive) ?? false;
70
- // Check for trust level based inclusion
71
- const has_trust_level = spec.trust !== undefined;
72
- const include_by_trust = has_trust_level && is_csp_trusted(required_trust, spec.trust);
73
- // Include the source if either condition is met
74
- return explicitly_included || include_by_trust;
75
- })
76
- .map((spec) => spec.source);
77
- if (sources_to_add.length > 0) {
78
- directives[directive] = [...value, ...sources_to_add];
96
+ else if (value !== undefined) {
97
+ assign(directive, value);
79
98
  }
80
- }
99
+ });
81
100
  }
82
- // Apply directive overrides/transformations
83
- if (directives_option) {
84
- for (const [key, value_or_fn] of Object.entries(directives_option)) {
85
- const directive = parse_csp_directive(key);
86
- if (directive === null) {
87
- throw new Error(`Invalid directive in options.directives: ${key}`);
88
- }
89
- const current = directives[directive];
90
- const result = typeof value_or_fn === 'function' ? value_or_fn(current) : value_or_fn;
91
- // Handle `undefined` too just in case
92
- if (result == null) {
93
- delete directives[directive]; // eslint-disable-line @typescript-eslint/no-dynamic-delete
94
- }
95
- else {
96
- directives[directive] = structuredClone(result);
101
+ // Stage 4: output validation — empty arrays and mixed `'none'` are invalid CSP.
102
+ for (const [key, value] of Object.entries(directives)) {
103
+ if (typeof value === 'boolean')
104
+ continue;
105
+ if (!Array.isArray(value)) {
106
+ throw new Error(`Directive '${key}' has an invalid value: expected an array of sources or a boolean, ` +
107
+ `got ${value === null ? 'null' : typeof value}.`);
108
+ }
109
+ if (value.length === 0) {
110
+ throw new Error(`Directive '${key}' has an empty array. ` +
111
+ `Use ['none'] to forbid all sources, or omit the directive entirely.`);
112
+ }
113
+ // Element-level type check — the `CspSource` template-string type gates this at the
114
+ // type layer, but `as any` callers can slip non-strings through. A non-string source
115
+ // would render as `undefined` / `[object Object]` in the emitted CSP header.
116
+ for (let i = 0; i < value.length; i++) {
117
+ const v = value[i];
118
+ if (typeof v !== 'string') {
119
+ throw new Error(`Directive '${key}' has a non-string source at index ${i}: got ${v === null ? 'null' : typeof v}.`);
97
120
  }
98
121
  }
122
+ if (value.length > 1 && value.includes('none')) {
123
+ throw new Error(`Directive '${key}' has 'none' alongside other tokens (${value.join(', ')}). ` +
124
+ `'none' must appear alone in CSP.`);
125
+ }
99
126
  }
100
127
  return directives;
101
- }
128
+ };
102
129
  export const parse_csp_directive = (directive) => typeof directive === 'string' && csp_directive_spec_by_name.has(directive)
103
130
  ? directive
104
131
  : null;
105
- export const csp_trust_levels = ['low', 'medium', 'high'];
106
- /**
107
- * Numeric values for CSP trust levels. See `csp_trust_levels`.
108
- * Lower is less trusted.
109
- * Includes `undefined` in the type for safety.
110
- */
111
- export const csp_trust_level_value = {
112
- low: 0,
113
- medium: 1,
114
- high: 2,
115
- };
116
- /**
117
- * Validates and extracts a CSP trust level from an unknown value.
118
- */
119
- export const parse_csp_trust_level = (trust) => csp_trust_levels.includes(trust) ? trust : null;
132
+ const is_none = (value) => Array.isArray(value) && value.length === 1 && value[0] === 'none';
120
133
  /**
121
- * Determines if a granted trust level is sufficient to satisfy a required trust level.
134
+ * Iterate over a per-directive options map, validating that every key is a known directive.
135
+ * Throws if any key fails to parse as a `CspDirective`, mentioning `source_label` so the
136
+ * error pinpoints which option (`replace_defaults`, `extend`, or `overrides`) was bad.
122
137
  *
123
- * Trust levels have the following hierarchy:
124
- * - 'high' sources can be used in high, medium, and low trust directives (highest privilege)
125
- * - 'medium' sources can be used in medium and low trust directives
126
- * - 'low' sources can only be used in low trust directives (lowest privilege)
138
+ * Also guards against non-object `source` values (e.g. `extend: [undefined]`, `extend: ['oops']`)
139
+ * so callers get a friendly library error instead of a cryptic native `TypeError` from
140
+ * `Object.entries`.
127
141
  */
128
- export const is_csp_trusted = (required_trust, granted_trust) => {
129
- const required_value = required_trust && csp_trust_level_value[required_trust];
130
- const granted_value = granted_trust && csp_trust_level_value[granted_trust];
131
- if (required_value == null || granted_value == null) {
132
- return false;
142
+ const for_each_directive = (source, source_label, fn) => {
143
+ if (source === null || typeof source !== 'object') {
144
+ const got = source === null ? 'null' : typeof source;
145
+ throw new Error(`Invalid entry in options.${source_label}: expected an object, got ${got}.`);
146
+ }
147
+ for (const [key, value] of Object.entries(source)) {
148
+ const directive = parse_csp_directive(key);
149
+ if (directive === null) {
150
+ throw new Error(`Invalid directive in options.${source_label}: ${key}`);
151
+ }
152
+ fn(directive, value);
133
153
  }
134
- // A source with higher trust privilege (higher value)
135
- // can be used in a directive with less privilege (lower value).
136
- return granted_value >= required_value;
137
154
  };
138
- /**
139
- * Helper to check if a directive value is `['none']`,
140
- * or more precisely for robustness with malformed values, checks for an array with `'none'`.
141
- */
142
- const is_none_directive = (value) => Array.isArray(value) && value.includes('none');
143
155
  export const COLOR_SCHEME_SCRIPT_HASH = 'sha256-QOxqn7EUzb3ydF9SALJoJGWSvywW9R0AfTDSenB83Z8=';
144
156
  /**
145
- * The base CSP directive defaults.
157
+ * The library CSP directive defaults — directives enabled out of the box.
146
158
  * Prioritizes safety but loosens around media and styles, relying on defense-in-depth.
147
- * Customizable via `CreateCspDirectivesOptions`.
159
+ * WASM compile is allowed (`'wasm-unsafe-eval'` on `script-src` and `worker-src`); `eval` is not.
160
+ *
161
+ * Directives not listed here (`report-to`, `require-trusted-types-for`, `trusted-types`,
162
+ * `sandbox`) are intentionally absent by default — opt in via `replace_defaults` or `overrides`.
163
+ *
164
+ * Customizable via `CreateCspDirectivesOptions.replace_defaults`.
148
165
  */
149
166
  export const csp_directive_value_defaults = {
150
167
  'default-src': ['none'],
151
- 'script-src': ['self', COLOR_SCHEME_SCRIPT_HASH], // Eval is opt-in, scripting is locked down except for self and the color scheme loader script
152
- 'script-src-elem': ['self', COLOR_SCHEME_SCRIPT_HASH], // Block script elements except for self and the color scheme loader
168
+ // `'wasm-unsafe-eval'` permits WASM compile/instantiate only — `eval` and `new Function`
169
+ // remain blocked. Needed for `@fuzdev/fuz_util/hash_blake3` and any other WASM in the page.
170
+ // Pre-2022 browsers ignore the keyword and block WASM; if you need them, override with `'unsafe-eval'`.
171
+ 'script-src': ['self', 'wasm-unsafe-eval', COLOR_SCHEME_SCRIPT_HASH],
172
+ 'script-src-elem': ['self', COLOR_SCHEME_SCRIPT_HASH], // Block script elements except for self and the color scheme loader (WASM compile is gated by script-src, not script-src-elem)
153
173
  'script-src-attr': ['none'], // Block scripts in HTML attributes
154
174
  'style-src': ['self', 'unsafe-inline'], // Main style directive (uses unsafe-inline but network connections are disallowed by other directives)
155
175
  'style-src-elem': ['self', 'unsafe-inline'], // Style elements (standalone stylesheets)
@@ -163,55 +183,17 @@ export const csp_directive_value_defaults = {
163
183
  'frame-src': ['self'], // Frames/iframes
164
184
  'frame-ancestors': ['self'], // Control what can embed this page
165
185
  'form-action': ['self'], // Form submission targets
166
- 'worker-src': ['self', 'blob:'], // Web workers
186
+ // `'wasm-unsafe-eval'` mirrors the script-src allowance so WASM compiled inside a Web Worker also works.
187
+ 'worker-src': ['self', 'blob:', 'wasm-unsafe-eval'], // Web workers
167
188
  'object-src': ['none'], // Block plugins (Flash, Java, etc.)
168
189
  'base-uri': ['none'], // Prevent base tag hijacking
169
190
  'upgrade-insecure-requests': true, // Upgrade http to https
170
- 'report-to': null, // Report violations (e.g. `'/csp-violation-report'`)
171
- 'require-trusted-types-for': null,
172
- 'trusted-types': null,
173
- sandbox: null,
174
- };
175
- /**
176
- * Sources that meet this trust requirement are included for it by default.
177
- * If null, no trusted sources are added to the directive automatically.
178
- * Directives that don't support sources or default to `['none']` are null.
179
- *
180
- * Feedback is welcome, please see the issues - https://github.com/fuzdev/fuz_ui/issues
181
- */
182
- export const csp_directive_required_trust_defaults = {
183
- 'default-src': null,
184
- 'script-src': 'high',
185
- 'script-src-elem': 'high',
186
- 'script-src-attr': null,
187
- 'style-src': 'medium',
188
- 'style-src-elem': 'medium',
189
- 'style-src-attr': 'medium',
190
- 'img-src': 'low',
191
- 'media-src': 'low',
192
- 'font-src': 'low',
193
- 'manifest-src': null,
194
- 'child-src': null,
195
- 'connect-src': 'medium',
196
- 'frame-src': 'medium',
197
- 'frame-ancestors': 'medium',
198
- 'form-action': 'medium',
199
- 'worker-src': 'medium',
200
- 'object-src': null,
201
- 'base-uri': null,
202
- 'upgrade-insecure-requests': null,
203
- 'report-to': null,
204
- 'require-trusted-types-for': null,
205
- 'trusted-types': null,
206
- sandbox: null,
207
191
  };
208
192
  /**
209
193
  * Static data descriptors for the CSP directives.
210
194
  * Fuz excludes deprecated directives, so those are intentionally omitted,
211
195
  * but any newer missing directives are bugs.
212
196
  *
213
- * Could be co-located but is currently here to keep that module smaller.
214
- *
215
197
  * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy}
216
198
  */
217
199
  export const csp_directive_specs = [
@@ -1,6 +1,16 @@
1
- import type { CspSourceSpec } from './csp.ts';
1
+ import type { CspDirectives } from './csp.ts';
2
2
  /**
3
- * Trusted sources owned by fuz.dev.
3
+ * Per-directive sources that allow full interop between fuzdev/sister sites
4
+ * (`*.fuz.dev`, `*.zzz.software`) — loading assets and APIs from each other,
5
+ * and iframing in both directions.
6
+ *
7
+ * Pass into `create_csp_directives({extend: [csp_directives_of_fuzdev]})`.
8
+ * Intended for sites within the ecosystem; external apps usually want a
9
+ * narrower, hand-written allow-list.
10
+ *
11
+ * Deliberately scoped — `script-src`, `style-src`, `worker-src`, etc. are not
12
+ * granted, even between sister sites. Add at the call site if a specific page
13
+ * needs them.
4
14
  */
5
- export declare const csp_trusted_sources_of_fuzdev: Array<CspSourceSpec>;
15
+ export declare const csp_directives_of_fuzdev: Partial<CspDirectives>;
6
16
  //# sourceMappingURL=csp_of_fuzdev.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"csp_of_fuzdev.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/csp_of_fuzdev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,UAAU,CAAC;AAE5C;;GAEG;AACH,eAAO,MAAM,6BAA6B,EAAE,KAAK,CAAC,aAAa,CAK9D,CAAC"}
1
+ {"version":3,"file":"csp_of_fuzdev.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/csp_of_fuzdev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,UAAU,CAAC;AAE5C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,EAAE,OAAO,CAAC,aAAa,CAW3D,CAAC"}
@@ -1,9 +1,25 @@
1
1
  /**
2
- * Trusted sources owned by fuz.dev.
2
+ * Per-directive sources that allow full interop between fuzdev/sister sites
3
+ * (`*.fuz.dev`, `*.zzz.software`) — loading assets and APIs from each other,
4
+ * and iframing in both directions.
5
+ *
6
+ * Pass into `create_csp_directives({extend: [csp_directives_of_fuzdev]})`.
7
+ * Intended for sites within the ecosystem; external apps usually want a
8
+ * narrower, hand-written allow-list.
9
+ *
10
+ * Deliberately scoped — `script-src`, `style-src`, `worker-src`, etc. are not
11
+ * granted, even between sister sites. Add at the call site if a specific page
12
+ * needs them.
3
13
  */
4
- export const csp_trusted_sources_of_fuzdev = [
5
- { source: 'https://*.fuz.dev/', trust: 'low' },
6
- { source: 'https://*.zzz.software/', trust: 'low' },
7
- // if needed
8
- // {source: 'https://fuzdev.github.io/', trust: 'low'},
9
- ];
14
+ export const csp_directives_of_fuzdev = {
15
+ 'img-src': ['https://*.fuz.dev/', 'https://*.zzz.software/'],
16
+ 'media-src': ['https://*.fuz.dev/', 'https://*.zzz.software/'],
17
+ 'font-src': ['https://*.fuz.dev/', 'https://*.zzz.software/'],
18
+ 'connect-src': ['https://*.fuz.dev/', 'https://*.zzz.software/'],
19
+ 'frame-src': ['https://*.fuz.dev/', 'https://*.zzz.software/'],
20
+ 'frame-ancestors': ['https://*.fuz.dev/', 'https://*.zzz.software/'],
21
+ // `child-src` is intentionally omitted — it defaults to `['none']`, and `extend` cannot
22
+ // append to a `'none'`-valued directive. Including it here would break the common
23
+ // `create_csp_directives({extend: [csp_directives_of_fuzdev]})` call. `frame-src` is its
24
+ // fallback target anyway, so direct opt-in via `frame-src` is the supported path.
25
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"dimensions.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/dimensions.svelte.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAU;IACtB,KAAK,EAAE,MAAM,CAAa;IAC1B,MAAM,EAAE,MAAM,CAAa;CAC3B"}
1
+ {"version":3,"file":"dimensions.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/dimensions.svelte.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAU;IACtB,KAAK,EAAE,MAAM,CAAiB;IAC9B,MAAM,EAAE,MAAM,CAAiB;CAC/B"}
@@ -1,4 +1,4 @@
1
1
  export class Dimensions {
2
- width = $state(0);
3
- height = $state(0);
2
+ width = $state.raw(0);
3
+ height = $state.raw(0);
4
4
  }
@@ -25,7 +25,7 @@ export declare class Library {
25
25
  readonly package_json: {
26
26
  [x: string]: unknown;
27
27
  name: string;
28
- version: string;
28
+ version?: string | undefined;
29
29
  private?: boolean | undefined;
30
30
  description?: string | undefined;
31
31
  tagline?: string | undefined;
@@ -81,7 +81,7 @@ export const library_generate = (input) => {
81
81
  // Phase 1: Analyze all modules and collect re-exports
82
82
  const source_json = {
83
83
  name: package_json.name,
84
- version: package_json.version,
84
+ version: package_json.version || '',
85
85
  modules,
86
86
  };
87
87
  // Collect re-exports for phase 2 merging
@@ -1 +1 @@
1
- {"version":3,"file":"style_variable_helpers.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/style_variable_helpers.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAK/D,qBAAa,qBAAqB;IACjC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAa;gBAE5B,OAAO,GAAE,aAAa,GAAG,IAAW;CAGhD;AAED,eAAO,MAAM,yBAAyB;;;CAAwD,CAAC"}
1
+ {"version":3,"file":"style_variable_helpers.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/style_variable_helpers.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAK/D,qBAAa,qBAAqB;IACjC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAiB;gBAEhC,OAAO,GAAE,aAAa,GAAG,IAAW;CAGhD;AAED,eAAO,MAAM,yBAAyB;;;CAAwD,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { create_context } from './context_helpers.js';
2
2
  // TODO maybe change this to a generic wrapper class for any value?
3
3
  export class SelectedStyleVariable {
4
- value = $state();
4
+ value = $state.raw();
5
5
  constructor(initial = null) {
6
6
  this.value = initial;
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"theme_state.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/theme_state.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,WAAW,EAAE,KAAK,KAAK,EAAC,MAAM,0BAA0B,CAAC;AAOrF,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,EAAE,WAAW,CAAC;CAC1B;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;AAExD,qBAAa,UAAU;IACtB,KAAK,EAAE,KAAK,CAAa;IACzB,YAAY,EAAE,WAAW,CAAa;gBAE1B,OAAO,CAAC,EAAE,iBAAiB;IAUvC,MAAM,IAAI,cAAc;CAMxB;AACD,eAAO,MAAM,mBAAmB;2CAAwB,UAAU;4BAAV,UAAU;uBAAV,UAAU,WAAV,UAAU;CAAG,CAAC;AAEtE,eAAO,MAAM,iBAAiB,GAAI,cAAc,WAAW,GAAG,IAAI,KAAG,IAOpE,CAAC;AAEF,eAAO,MAAM,wBAAwB,qBAAqB,CAAC;AAC3D,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C,eAAO,MAAM,iBAAiB,GAC7B,cAAc,WAAW,GAAG,IAAI,EAChC,YAA8B,KAC5B,IAEF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC7B,WAAU,WAAoB,EAC9B,YAA8B,KAC5B,WAA4E,CAAC;AAEhF,eAAO,MAAM,UAAU,GAAI,OAAO,KAAK,GAAG,IAAI,EAAE,YAAuB,KAAG,IAEzE,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,WAAU,KAA0B,EAAE,YAAuB,KAAG,KAC3C,CAAC"}
1
+ {"version":3,"file":"theme_state.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/theme_state.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,WAAW,EAAE,KAAK,KAAK,EAAC,MAAM,0BAA0B,CAAC;AAOrF,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,EAAE,WAAW,CAAC;CAC1B;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;AAExD,qBAAa,UAAU;IACtB,KAAK,EAAE,KAAK,CAAiB;IAC7B,YAAY,EAAE,WAAW,CAAiB;gBAE9B,OAAO,CAAC,EAAE,iBAAiB;IAUvC,MAAM,IAAI,cAAc;CAMxB;AACD,eAAO,MAAM,mBAAmB;2CAAwB,UAAU;4BAAV,UAAU;uBAAV,UAAU,WAAV,UAAU;CAAG,CAAC;AAEtE,eAAO,MAAM,iBAAiB,GAAI,cAAc,WAAW,GAAG,IAAI,KAAG,IAOpE,CAAC;AAEF,eAAO,MAAM,wBAAwB,qBAAqB,CAAC;AAC3D,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C,eAAO,MAAM,iBAAiB,GAC7B,cAAc,WAAW,GAAG,IAAI,EAChC,YAA8B,KAC5B,IAEF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC7B,WAAU,WAAoB,EAC9B,YAA8B,KAC5B,WAA4E,CAAC;AAEhF,eAAO,MAAM,UAAU,GAAI,OAAO,KAAK,GAAG,IAAI,EAAE,YAAuB,KAAG,IAEzE,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,WAAU,KAA0B,EAAE,YAAuB,KAAG,KAC3C,CAAC"}
@@ -4,8 +4,8 @@ import { BROWSER } from 'esm-env';
4
4
  import { create_context } from './context_helpers.js';
5
5
  import { load_from_storage, save_to_storage } from './storage.js';
6
6
  export class ThemeState {
7
- theme = $state();
8
- color_scheme = $state();
7
+ theme = $state.raw();
8
+ color_scheme = $state.raw();
9
9
  constructor(options) {
10
10
  const theme = options?.theme ?? default_themes[0];
11
11
  const color_scheme = options?.color_scheme ?? 'auto';
package/dist/tome.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import type { Component } from 'svelte';
2
2
  import { z } from 'zod';
3
3
  export declare const Tome: z.ZodObject<{
4
- name: z.ZodString;
4
+ slug: z.ZodString;
5
+ title: z.ZodOptional<z.ZodString>;
5
6
  category: z.ZodString;
6
7
  Component: z.ZodCustom<Component<any, any, string>, Component<any, any, string>>;
7
8
  related_tomes: z.ZodArray<z.ZodString>;
@@ -12,13 +13,17 @@ export type Tome = z.infer<typeof Tome>;
12
13
  /**
13
14
  * @param hash - URL fragment to append, with or without the `#`
14
15
  */
15
- export declare const to_tome_pathname: (item: Tome | string, docs_path?: string, hash?: string) => string;
16
+ export declare const tome_to_pathname: (item: Tome | string, docs_path?: string, hash?: string) => string;
17
+ /**
18
+ * The display label for a tome — its `title` if set, else its `slug`.
19
+ */
20
+ export declare const tome_to_title: (tome: Tome) => string;
16
21
  export declare const tomes_context: {
17
22
  get: (error_message?: string) => () => Map<string, Tome>;
18
23
  get_maybe: () => (() => Map<string, Tome>) | undefined;
19
24
  set: (value: () => Map<string, Tome>) => () => Map<string, Tome>;
20
25
  };
21
- export declare const get_tome_by_name: (name: string) => Tome;
26
+ export declare const tome_get_by_slug: (slug: string) => Tome;
22
27
  export declare const tome_context: {
23
28
  get: (error_message?: string) => () => Tome;
24
29
  get_maybe: () => (() => Tome) | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"tome.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tome.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAMtB,eAAO,MAAM,IAAI;;;;;;;iBAQf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC5B,MAAM,IAAI,GAAG,MAAM,EACnB,kBAA6B,EAC7B,OAAO,MAAM,KACX,MAIF,CAAC;AAEF,eAAO,MAAM,aAAa;2CAAwB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;4BAAjB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;uBAAjB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,WAAjB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;CAAG,CAAC;AAEvE,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,IAK/C,CAAC;AAEF,eAAO,MAAM,YAAY;2CAAwB,IAAI;4BAAJ,IAAI;uBAAJ,IAAI,WAAJ,IAAI;CAAG,CAAC"}
1
+ {"version":3,"file":"tome.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tome.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAMtB,eAAO,MAAM,IAAI;;;;;;;;iBAoBf,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAExC;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC5B,MAAM,IAAI,GAAG,MAAM,EACnB,kBAA6B,EAC7B,OAAO,MAAM,KACX,MAIF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,IAAI,KAAG,MAAiC,CAAC;AAE7E,eAAO,MAAM,aAAa;2CAAwB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;4BAAjB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;uBAAjB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,WAAjB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;CAAG,CAAC;AAEvE,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,IAK/C,CAAC;AAEF,eAAO,MAAM,YAAY;2CAAwB,IAAI;4BAAJ,IAAI;uBAAJ,IAAI,WAAJ,IAAI;CAAG,CAAC"}
package/dist/tome.js CHANGED
@@ -2,9 +2,21 @@ import { resolve } from '$app/paths';
2
2
  import { z } from 'zod';
3
3
  import { ensure_start } from '@fuzdev/fuz_util/string.js';
4
4
  import { create_context } from './context_helpers.js';
5
- import { DOCS_PATH_DEFAULT, docs_slugify } from './docs_helpers.svelte.js';
5
+ import { DOCS_PATH_DEFAULT } from './docs_helpers.svelte.js';
6
6
  export const Tome = z.object({
7
- name: z.string(),
7
+ /**
8
+ * Stable identifier and URL path segment — must be a URL-safe slug
9
+ * (used directly as the route segment, the lookup key, and in
10
+ * `related_tomes` cross-references). Set `title` for the display label.
11
+ */
12
+ slug: z.string(),
13
+ /**
14
+ * Human-readable display label shown in menus, headings, and links.
15
+ * Falls back to `slug` when omitted, so set `title` to give multi-word or
16
+ * specially cased tomes a readable label (e.g. `slug: 'vite-plugin'` →
17
+ * `title: 'vite plugin'`).
18
+ */
19
+ title: z.string().optional(),
8
20
  // TODO maybe now this makes sense with mdz? summary: z.string(),
9
21
  category: z.string(),
10
22
  Component: z.custom(),
@@ -15,17 +27,21 @@ export const Tome = z.object({
15
27
  /**
16
28
  * @param hash - URL fragment to append, with or without the `#`
17
29
  */
18
- export const to_tome_pathname = (item, docs_path = DOCS_PATH_DEFAULT, hash) => {
19
- const name = typeof item === 'string' ? item : item.name;
20
- const path = docs_path + '/' + docs_slugify(name);
30
+ export const tome_to_pathname = (item, docs_path = DOCS_PATH_DEFAULT, hash) => {
31
+ const slug = typeof item === 'string' ? item : item.slug;
32
+ const path = docs_path + '/' + slug;
21
33
  return resolve((hash ? path + ensure_start(hash, '#') : path));
22
34
  };
35
+ /**
36
+ * The display label for a tome — its `title` if set, else its `slug`.
37
+ */
38
+ export const tome_to_title = (tome) => tome.title ?? tome.slug;
23
39
  export const tomes_context = create_context();
24
- export const get_tome_by_name = (name) => {
40
+ export const tome_get_by_slug = (slug) => {
25
41
  const get_tomes = tomes_context.get();
26
- const tome = get_tomes().get(name);
42
+ const tome = get_tomes().get(slug);
27
43
  if (!tome)
28
- throw Error(`unable to find tome "${name}"`);
44
+ throw Error(`unable to find tome "${slug}"`);
29
45
  return tome;
30
46
  };
31
47
  export const tome_context = create_context();
@@ -98,6 +98,15 @@ export declare const tsdoc_parse: (node: ts.Node, source_file: ts.SourceFile) =>
98
98
  * @mutates declaration - adds doc_comment, deprecated_message, examples, see_also, throws, since fields
99
99
  */
100
100
  export declare const tsdoc_apply_to_declaration: (declaration: DeclarationJson, tsdoc: TsdocParsedComment | undefined) => void;
101
+ /**
102
+ * Concatenates a JSDoc comment (string or node array) into plain text, preserving `{@link ...}`.
103
+ *
104
+ * `JSDocLink` / `JSDocLinkCode` / `JSDocLinkPlain` nodes have empty `.text` — the identifier
105
+ * lives on `.name`, not `.text`. Using `.text` alone silently drops link content; we fall back
106
+ * to the source-text representation for link nodes so `{@link Foo}` survives intact for downstream
107
+ * renderers (see `tsdoc_mdz.ts`).
108
+ */
109
+ export declare const tsdoc_comment_to_text: (comment: string | ts.NodeArray<ts.JSDocComment>, source_file: ts.SourceFile) => string;
101
110
  /**
102
111
  * Clean raw JSDoc comment text by removing comment markers and leading asterisks.
103
112
  *
@@ -1 +1 @@
1
- {"version":3,"file":"tsdoc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tsdoc_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,MAAM,CAAC,EAAE,KAAK,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACrD,oCAAoC;IACpC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,WAAW,GACvB,MAAM,EAAE,CAAC,IAAI,EACb,aAAa,EAAE,CAAC,UAAU,KACxB,kBAAkB,GAAG,SAyFvB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,GACtC,aAAa,eAAe,EAC5B,OAAO,kBAAkB,GAAG,SAAS,KACnC,IAmBF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAAI,cAAc,MAAM,KAAG,MAAM,GAAG,SAUnE,CAAC"}
1
+ {"version":3,"file":"tsdoc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/tsdoc_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,MAAM,CAAC,EAAE,KAAK,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACrD,oCAAoC;IACpC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,WAAW,GACvB,MAAM,EAAE,CAAC,IAAI,EACb,aAAa,EAAE,CAAC,UAAU,KACxB,kBAAkB,GAAG,SAoFvB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,GACtC,aAAa,eAAe,EAC5B,OAAO,kBAAkB,GAAG,SAAS,KACnC,IAmBF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GACjC,SAAS,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,YAAY,CAAC,EAC/C,aAAa,EAAE,CAAC,UAAU,KACxB,MAGF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAAI,cAAc,MAAM,KAAG,MAAM,GAAG,SAUnE,CAAC"}