hono-decks 0.2.0 → 0.2.2

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/mod.js CHANGED
@@ -1,437 +1,448 @@
1
- // src/server/router.ts
2
- import { Hono } from "hono";
3
- import { raw as raw2 } from "hono/html";
4
-
5
- // src/deck/model.ts
6
- var SLIDE_TRANSITIONS = [
7
- "none",
8
- "fade",
9
- "fade-out",
10
- "slide-left",
11
- "slide-right",
12
- "slide-up",
13
- "slide-down",
14
- "view-transition"
15
- ];
16
-
17
- // src/renderer/jsx-renderer.ts
1
+ import { raw } from "hono/html";
18
2
  import { jsx } from "hono/jsx/jsx-runtime";
19
3
  import { HtmlEscapedCallbackPhase, resolveCallback } from "hono/utils/html";
20
- var builtInSlideComponents = defineSlideComponents({
21
- Fire: (props) => {
22
- if (props.order !== void 0) {
23
- throw new Error('The Fire "order" prop is not supported. Fires reveal in source order.');
24
- }
25
- const effect = stringProp(props.effect);
26
- const at = fireAtProp(props.at);
27
- return jsx("div", {
28
- "data-hono-decks-fire": true,
29
- ...at ? { "data-fire-at": at } : {},
30
- ...effect ? { "data-fire-effect": safeToken(effect).toLowerCase() } : {},
31
- children: props.children
32
- });
33
- },
34
- Hero: (props) => jsx("section", {
35
- class: `mdx-hero${props.featured === true ? " is-featured" : ""}${props.image || props.src ? " has-image" : ""}`,
36
- "data-component": "Hero",
37
- children: [
38
- heroImage(props),
39
- jsx("div", {
40
- class: "mdx-hero-copy",
41
- children: [
42
- typeof props.eyebrow === "string" && props.eyebrow ? jsx("p", { class: "mdx-hero-eyebrow", children: props.eyebrow }) : "",
43
- typeof props.title === "string" && props.title ? jsx("h1", { children: props.title }) : "",
44
- typeof props.subtitle === "string" && props.subtitle ? jsx("p", { class: "mdx-hero-subtitle", children: props.subtitle }) : typeof props.description === "string" && props.description ? jsx("p", { class: "mdx-hero-subtitle", children: props.description }) : ""
45
- ]
46
- })
47
- ]
48
- }),
49
- CodeBlock: (props) => {
50
- const lang = stringProp(props.lang);
51
- const filename = stringProp(props.filename ?? props.title);
52
- const highlight = stringProp(props.highlight);
53
- const code = codeBlockText(props.children);
54
- const highlightedHtml = typeof props.highlightedHtml === "string" ? props.highlightedHtml : void 0;
55
- return jsx("figure", {
56
- class: "hono-decks-code-block",
57
- ...lang ? { "data-lang": lang } : {},
58
- ...filename ? { "data-filename": filename } : {},
59
- ...highlight ? { "data-highlight": highlight } : {},
60
- children: [
61
- filename ? jsx("figcaption", { class: "hono-decks-code-caption", children: filename }) : "",
62
- highlightedHtml ? jsx("div", {
63
- class: "hono-decks-code-highlight",
64
- dangerouslySetInnerHTML: { __html: highlightedHtml }
65
- }) : jsx("pre", {
66
- children: jsx("code", {
67
- ...lang ? { class: `language-${safeToken(lang)}`, "data-lang": lang } : {},
68
- children: code
69
- })
70
- })
71
- ]
72
- });
73
- },
74
- EmbedFrame: (props) => {
75
- const src = stringProp(props.src);
76
- const provider = stringProp(props.provider)?.trim().toLowerCase();
77
- const title = stringProp(props.title) ?? "Embedded content";
78
- const aspectRatio = stringProp(props.aspectRatio) ?? "16 / 9";
79
- const loading = stringProp(props.loading) ?? "lazy";
80
- const allow = stringProp(props.allow) ?? "fullscreen; picture-in-picture";
81
- const sandbox = props.sandbox === false ? void 0 : stringProp(props.sandbox) ?? "allow-scripts allow-same-origin allow-presentation allow-popups";
82
- const referrerPolicy = stringProp(props.referrerPolicy ?? props.referrerpolicy) ?? "strict-origin-when-cross-origin";
83
- const fallbackHref = stringProp(props.fallbackHref ?? props.fallbackUrl ?? props.href) ?? src;
84
- const fallback = codeBlockText(props.children) || "Open embed";
85
- const printPoster = provider === "youtube" ? youtubePrintPoster(src) : void 0;
86
- return jsx("figure", {
87
- class: "hono-decks-embed-frame",
88
- "data-component": "EmbedFrame",
89
- ...provider ? { "data-provider": safeToken(provider).toLowerCase() } : {},
90
- children: [
91
- jsx("div", {
92
- class: "hono-decks-embed-viewport",
93
- style: `aspect-ratio:${safeAspectRatio(aspectRatio)}`,
94
- children: [
95
- src ? jsx("iframe", {
96
- src,
97
- title,
98
- loading,
99
- referrerpolicy: referrerPolicy,
100
- ...sandbox ? { sandbox } : {},
101
- ...allow ? { allow } : {},
102
- allowfullscreen: true
103
- }) : "",
104
- fallbackHref ? jsx("a", {
105
- class: "hono-decks-embed-print-fallback",
106
- href: fallbackHref,
107
- children: [
108
- printPoster ? jsx("img", {
109
- class: "hono-decks-embed-print-poster",
110
- src: printPoster,
111
- alt: `${title} thumbnail`
112
- }) : "",
113
- jsx("span", { children: fallback })
114
- ]
115
- }) : ""
116
- ]
117
- }),
118
- src ? jsx("figcaption", {
119
- class: "hono-decks-embed-fallback",
120
- children: jsx("a", { href: fallbackHref, target: "_blank", rel: "noreferrer", children: fallback })
121
- }) : ""
122
- ]
123
- });
124
- },
125
- SocialEmbed: (props) => {
126
- const href = stringProp(props.href ?? props.url);
127
- const provider = stringProp(props.provider ?? props.service);
128
- const author = stringProp(props.author);
129
- const label = stringProp(props.label) ?? (provider ? `Open on ${provider}` : "Open social post");
130
- const quote = codeBlockText(props.children);
131
- return jsx("figure", {
132
- class: "hono-decks-social-embed",
133
- "data-component": "SocialEmbed",
134
- ...provider ? { "data-provider": safeToken(provider).toLowerCase() } : {},
135
- children: jsx("blockquote", {
136
- class: "hono-decks-social-card",
137
- ...href ? { cite: href } : {},
138
- children: [
139
- quote ? jsx("p", { children: quote }) : "",
140
- jsx("footer", {
141
- children: [
142
- author ? jsx("span", { class: "hono-decks-social-author", children: author }) : "",
143
- href ? jsx("a", {
144
- href,
145
- target: "_blank",
146
- rel: "noreferrer",
147
- children: label
148
- }) : ""
149
- ]
150
- })
151
- ]
152
- })
153
- });
154
- },
155
- TweetEmbed: (props) => {
156
- const href = stringProp(props.href ?? props.url);
157
- const label = stringProp(props.label) ?? "Open post on X";
158
- return jsx("figure", {
159
- class: "hono-decks-tweet-embed",
160
- "data-component": "TweetEmbed",
161
- children: [
162
- jsx("blockquote", {
163
- class: "twitter-tweet",
164
- "data-dnt": "true",
165
- children: href ? jsx("a", {
166
- href,
167
- target: "_blank",
168
- rel: "noreferrer",
169
- children: label
170
- }) : label
171
- }),
172
- href ? jsx("script", {
173
- async: true,
174
- src: "https://platform.twitter.com/widgets.js",
175
- charset: "utf-8"
176
- }) : "",
177
- href ? jsx("a", {
178
- class: "hono-decks-tweet-print-fallback",
179
- href,
180
- children: label
181
- }) : ""
182
- ]
183
- });
184
- },
185
- LinkCard: (props) => {
186
- const href = stringProp(props.href ?? props.url);
187
- const title = stringProp(props.title) ?? href ?? "Link";
188
- const description = stringProp(props.description);
189
- const image = stringProp(props.image ?? props.imageUrl);
190
- const siteName = stringProp(props.siteName ?? props.site);
191
- const label = codeBlockText(props.children) || "Open link";
192
- return jsx("figure", {
193
- class: "hono-decks-link-card",
194
- "data-component": "LinkCard",
195
- children: href ? jsx("a", {
196
- class: "hono-decks-link-card-anchor",
197
- href,
198
- target: "_blank",
199
- rel: "noreferrer",
200
- children: [
201
- image ? jsx("img", { class: "hono-decks-link-card-image", src: image, alt: title }) : "",
202
- jsx("span", {
203
- class: "hono-decks-link-card-body",
204
- children: [
205
- siteName ? jsx("span", { class: "hono-decks-link-card-site", children: siteName }) : "",
206
- jsx("span", { class: "hono-decks-link-card-title", children: title }),
207
- description ? jsx("span", { class: "hono-decks-link-card-description", children: description }) : "",
208
- jsx("span", { class: "hono-decks-link-card-label", children: label })
209
- ]
210
- })
211
- ]
212
- }) : [
213
- image ? jsx("img", { class: "hono-decks-link-card-image", src: image, alt: title }) : "",
214
- siteName ? jsx("span", { class: "hono-decks-link-card-site", children: siteName }) : "",
215
- jsx("span", { class: "hono-decks-link-card-title", children: title }),
216
- description ? jsx("span", { class: "hono-decks-link-card-description", children: description }) : ""
217
- ]
218
- });
219
- }
4
+ //#region src/deck/model.ts
5
+ const SLIDE_TRANSITIONS = [
6
+ "none",
7
+ "fade",
8
+ "fade-out",
9
+ "slide-left",
10
+ "slide-right",
11
+ "slide-up",
12
+ "slide-down",
13
+ "view-transition"
14
+ ];
15
+ defineSlideComponents({
16
+ Fire: (props) => {
17
+ if (props.order !== void 0) throw new Error("The Fire \"order\" prop is not supported. Fires reveal in source order.");
18
+ const effect = stringProp(props.effect);
19
+ const at = fireAtProp(props.at);
20
+ return jsx("div", {
21
+ "data-hono-decks-fire": true,
22
+ ...at ? { "data-fire-at": at } : {},
23
+ ...effect ? { "data-fire-effect": safeToken(effect).toLowerCase() } : {},
24
+ children: props.children
25
+ });
26
+ },
27
+ Hero: (props) => jsx("section", {
28
+ class: `mdx-hero${props.featured === true ? " is-featured" : ""}${props.image || props.src ? " has-image" : ""}`,
29
+ "data-component": "Hero",
30
+ children: [heroImage(props), jsx("div", {
31
+ class: "mdx-hero-copy",
32
+ children: [
33
+ typeof props.eyebrow === "string" && props.eyebrow ? jsx("p", {
34
+ class: "mdx-hero-eyebrow",
35
+ children: props.eyebrow
36
+ }) : "",
37
+ typeof props.title === "string" && props.title ? jsx("h1", { children: props.title }) : "",
38
+ typeof props.subtitle === "string" && props.subtitle ? jsx("p", {
39
+ class: "mdx-hero-subtitle",
40
+ children: props.subtitle
41
+ }) : typeof props.description === "string" && props.description ? jsx("p", {
42
+ class: "mdx-hero-subtitle",
43
+ children: props.description
44
+ }) : ""
45
+ ]
46
+ })]
47
+ }),
48
+ CodeBlock: (props) => {
49
+ const lang = stringProp(props.lang);
50
+ const filename = stringProp(props.filename ?? props.title);
51
+ const highlight = stringProp(props.highlight);
52
+ const code = codeBlockText(props.children);
53
+ const highlightedHtml = typeof props.highlightedHtml === "string" ? props.highlightedHtml : void 0;
54
+ return jsx("figure", {
55
+ class: "hono-decks-code-block",
56
+ ...lang ? { "data-lang": lang } : {},
57
+ ...filename ? { "data-filename": filename } : {},
58
+ ...highlight ? { "data-highlight": highlight } : {},
59
+ children: [filename ? jsx("figcaption", {
60
+ class: "hono-decks-code-caption",
61
+ children: filename
62
+ }) : "", highlightedHtml ? jsx("div", {
63
+ class: "hono-decks-code-highlight",
64
+ dangerouslySetInnerHTML: { __html: highlightedHtml }
65
+ }) : jsx("pre", { children: jsx("code", {
66
+ ...lang ? {
67
+ class: `language-${safeToken(lang)}`,
68
+ "data-lang": lang
69
+ } : {},
70
+ children: code
71
+ }) })]
72
+ });
73
+ },
74
+ EmbedFrame: (props) => {
75
+ const src = stringProp(props.src);
76
+ const provider = stringProp(props.provider)?.trim().toLowerCase();
77
+ const title = stringProp(props.title) ?? "Embedded content";
78
+ const aspectRatio = stringProp(props.aspectRatio) ?? "16 / 9";
79
+ const loading = stringProp(props.loading) ?? "lazy";
80
+ const allow = stringProp(props.allow) ?? "fullscreen; picture-in-picture";
81
+ const sandbox = props.sandbox === false ? void 0 : stringProp(props.sandbox) ?? "allow-scripts allow-same-origin allow-presentation allow-popups";
82
+ const referrerPolicy = stringProp(props.referrerPolicy ?? props.referrerpolicy) ?? "strict-origin-when-cross-origin";
83
+ const fallbackHref = stringProp(props.fallbackHref ?? props.fallbackUrl ?? props.href) ?? src;
84
+ const fallback = codeBlockText(props.children) || "Open embed";
85
+ const printPoster = provider === "youtube" ? youtubePrintPoster(src) : void 0;
86
+ return jsx("figure", {
87
+ class: "hono-decks-embed-frame",
88
+ "data-component": "EmbedFrame",
89
+ ...provider ? { "data-provider": safeToken(provider).toLowerCase() } : {},
90
+ children: [jsx("div", {
91
+ class: "hono-decks-embed-viewport",
92
+ style: `aspect-ratio:${safeAspectRatio(aspectRatio)}`,
93
+ children: [src ? jsx("iframe", {
94
+ src,
95
+ title,
96
+ loading,
97
+ referrerpolicy: referrerPolicy,
98
+ ...sandbox ? { sandbox } : {},
99
+ ...allow ? { allow } : {},
100
+ allowfullscreen: true
101
+ }) : "", fallbackHref ? jsx("a", {
102
+ class: "hono-decks-embed-print-fallback",
103
+ href: fallbackHref,
104
+ children: [printPoster ? jsx("img", {
105
+ class: "hono-decks-embed-print-poster",
106
+ src: printPoster,
107
+ alt: `${title} thumbnail`
108
+ }) : "", jsx("span", { children: fallback })]
109
+ }) : ""]
110
+ }), src ? jsx("figcaption", {
111
+ class: "hono-decks-embed-fallback",
112
+ children: jsx("a", {
113
+ href: fallbackHref,
114
+ target: "_blank",
115
+ rel: "noreferrer",
116
+ children: fallback
117
+ })
118
+ }) : ""]
119
+ });
120
+ },
121
+ SocialEmbed: (props) => {
122
+ const href = stringProp(props.href ?? props.url);
123
+ const provider = stringProp(props.provider ?? props.service);
124
+ const author = stringProp(props.author);
125
+ const label = stringProp(props.label) ?? (provider ? `Open on ${provider}` : "Open social post");
126
+ const quote = codeBlockText(props.children);
127
+ return jsx("figure", {
128
+ class: "hono-decks-social-embed",
129
+ "data-component": "SocialEmbed",
130
+ ...provider ? { "data-provider": safeToken(provider).toLowerCase() } : {},
131
+ children: jsx("blockquote", {
132
+ class: "hono-decks-social-card",
133
+ ...href ? { cite: href } : {},
134
+ children: [quote ? jsx("p", { children: quote }) : "", jsx("footer", { children: [author ? jsx("span", {
135
+ class: "hono-decks-social-author",
136
+ children: author
137
+ }) : "", href ? jsx("a", {
138
+ href,
139
+ target: "_blank",
140
+ rel: "noreferrer",
141
+ children: label
142
+ }) : ""] })]
143
+ })
144
+ });
145
+ },
146
+ TweetEmbed: (props) => {
147
+ const href = stringProp(props.href ?? props.url);
148
+ const label = stringProp(props.label) ?? "Open post on X";
149
+ return jsx("figure", {
150
+ class: "hono-decks-tweet-embed",
151
+ "data-component": "TweetEmbed",
152
+ children: [
153
+ jsx("blockquote", {
154
+ class: "twitter-tweet",
155
+ "data-dnt": "true",
156
+ children: href ? jsx("a", {
157
+ href,
158
+ target: "_blank",
159
+ rel: "noreferrer",
160
+ children: label
161
+ }) : label
162
+ }),
163
+ href ? jsx("script", {
164
+ async: true,
165
+ src: "https://platform.twitter.com/widgets.js",
166
+ charset: "utf-8"
167
+ }) : "",
168
+ href ? jsx("a", {
169
+ class: "hono-decks-tweet-print-fallback",
170
+ href,
171
+ children: label
172
+ }) : ""
173
+ ]
174
+ });
175
+ },
176
+ LinkCard: (props) => {
177
+ const href = stringProp(props.href ?? props.url);
178
+ const title = stringProp(props.title) ?? href ?? "Link";
179
+ const description = stringProp(props.description);
180
+ const image = stringProp(props.image ?? props.imageUrl);
181
+ const siteName = stringProp(props.siteName ?? props.site);
182
+ const label = codeBlockText(props.children) || "Open link";
183
+ return jsx("figure", {
184
+ class: "hono-decks-link-card",
185
+ "data-component": "LinkCard",
186
+ children: href ? jsx("a", {
187
+ class: "hono-decks-link-card-anchor",
188
+ href,
189
+ target: "_blank",
190
+ rel: "noreferrer",
191
+ children: [image ? jsx("img", {
192
+ class: "hono-decks-link-card-image",
193
+ src: image,
194
+ alt: title
195
+ }) : "", jsx("span", {
196
+ class: "hono-decks-link-card-body",
197
+ children: [
198
+ siteName ? jsx("span", {
199
+ class: "hono-decks-link-card-site",
200
+ children: siteName
201
+ }) : "",
202
+ jsx("span", {
203
+ class: "hono-decks-link-card-title",
204
+ children: title
205
+ }),
206
+ description ? jsx("span", {
207
+ class: "hono-decks-link-card-description",
208
+ children: description
209
+ }) : "",
210
+ jsx("span", {
211
+ class: "hono-decks-link-card-label",
212
+ children: label
213
+ })
214
+ ]
215
+ })]
216
+ }) : [
217
+ image ? jsx("img", {
218
+ class: "hono-decks-link-card-image",
219
+ src: image,
220
+ alt: title
221
+ }) : "",
222
+ siteName ? jsx("span", {
223
+ class: "hono-decks-link-card-site",
224
+ children: siteName
225
+ }) : "",
226
+ jsx("span", {
227
+ class: "hono-decks-link-card-title",
228
+ children: title
229
+ }),
230
+ description ? jsx("span", {
231
+ class: "hono-decks-link-card-description",
232
+ children: description
233
+ }) : ""
234
+ ]
235
+ });
236
+ }
220
237
  });
221
238
  function defineSlideComponents(input) {
222
- const registry = {};
223
- for (const [name, value] of Object.entries(input)) {
224
- registry[name] = typeof value === "function" ? { component: value } : value;
225
- }
226
- return registry;
239
+ const registry = {};
240
+ for (const [name, value] of Object.entries(input)) registry[name] = typeof value === "function" ? { component: value } : value;
241
+ return registry;
227
242
  }
228
243
  function heroImage(props) {
229
- const image = typeof props.image === "string" ? props.image : typeof props.src === "string" ? props.src : void 0;
230
- if (!image) return "";
231
- const alt = typeof props.alt === "string" && props.alt ? props.alt : typeof props.title === "string" ? props.title : "Hero image";
232
- return jsx("img", { class: "mdx-hero-image", src: image, alt });
244
+ const image = typeof props.image === "string" ? props.image : typeof props.src === "string" ? props.src : void 0;
245
+ if (!image) return "";
246
+ return jsx("img", {
247
+ class: "mdx-hero-image",
248
+ src: image,
249
+ alt: typeof props.alt === "string" && props.alt ? props.alt : typeof props.title === "string" ? props.title : "Hero image"
250
+ });
233
251
  }
234
252
  function stringProp(value) {
235
- if (typeof value === "string") return value;
236
- if (typeof value === "number" || typeof value === "boolean") return String(value);
237
- return void 0;
253
+ if (typeof value === "string") return value;
254
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
238
255
  }
239
256
  function fireAtProp(value) {
240
- if (value === void 0 || value === null) return void 0;
241
- if (typeof value === "number") {
242
- if (Number.isInteger(value) && value >= 0) return String(value);
243
- throw new Error('The Fire "at" prop accepts a non-negative integer or a relative string such as "+1".');
244
- }
245
- if (typeof value === "string") {
246
- const at = value.trim();
247
- if (/^(?:\d+|[+-]\d+)$/.test(at)) return at;
248
- }
249
- throw new Error('The Fire "at" prop accepts a non-negative integer or a relative string such as "+1".');
257
+ if (value === void 0 || value === null) return void 0;
258
+ if (typeof value === "number") {
259
+ if (Number.isInteger(value) && value >= 0) return String(value);
260
+ throw new Error("The Fire \"at\" prop accepts a non-negative integer or a relative string such as \"+1\".");
261
+ }
262
+ if (typeof value === "string") {
263
+ const at = value.trim();
264
+ if (/^(?:\d+|[+-]\d+)$/.test(at)) return at;
265
+ }
266
+ throw new Error("The Fire \"at\" prop accepts a non-negative integer or a relative string such as \"+1\".");
250
267
  }
251
268
  function safeToken(value) {
252
- return value.trim().replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "text";
269
+ return value.trim().replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "text";
253
270
  }
254
271
  function safeAspectRatio(value) {
255
- return /^\s*\d+(\.\d+)?\s*(\/|:)\s*\d+(\.\d+)?\s*$/.test(value) ? value.replace(":", " / ") : "16 / 9";
272
+ return /^\s*\d+(\.\d+)?\s*(\/|:)\s*\d+(\.\d+)?\s*$/.test(value) ? value.replace(":", " / ") : "16 / 9";
256
273
  }
257
274
  function youtubePrintPoster(src) {
258
- if (!src) return void 0;
259
- try {
260
- const url = new URL(src);
261
- if (!["youtube.com", "www.youtube.com", "youtube-nocookie.com", "www.youtube-nocookie.com"].includes(url.hostname)) {
262
- return void 0;
263
- }
264
- const match = url.pathname.match(/^\/embed\/([A-Za-z0-9_-]+)$/);
265
- return match ? `https://i.ytimg.com/vi/${match[1]}/hqdefault.jpg` : void 0;
266
- } catch {
267
- return void 0;
268
- }
275
+ if (!src) return void 0;
276
+ try {
277
+ const url = new URL(src);
278
+ if (![
279
+ "youtube.com",
280
+ "www.youtube.com",
281
+ "youtube-nocookie.com",
282
+ "www.youtube-nocookie.com"
283
+ ].includes(url.hostname)) return;
284
+ const match = url.pathname.match(/^\/embed\/([A-Za-z0-9_-]+)$/);
285
+ return match ? `https://i.ytimg.com/vi/${match[1]}/hqdefault.jpg` : void 0;
286
+ } catch {
287
+ return;
288
+ }
269
289
  }
270
290
  function codeBlockText(value) {
271
- if (Array.isArray(value)) return value.map(codeBlockText).join("");
272
- if (value === null || value === void 0 || typeof value === "boolean") return "";
273
- if (typeof value === "string" || typeof value === "number") return String(value);
274
- if (isJsxValue(value)) return codeBlockText(value.props?.children);
275
- return String(value);
291
+ if (Array.isArray(value)) return value.map(codeBlockText).join("");
292
+ if (value === null || value === void 0 || typeof value === "boolean") return "";
293
+ if (typeof value === "string" || typeof value === "number") return String(value);
294
+ if (isJsxValue(value)) return codeBlockText(value.props?.children);
295
+ return String(value);
276
296
  }
277
297
  async function renderJsxValue(value) {
278
- const resolved = value instanceof Promise ? await value : value;
279
- if (typeof resolved === "string") return resolved;
280
- if (resolved === null || resolved === void 0 || typeof resolved === "boolean") return "";
281
- if (typeof resolved === "number") return String(resolved);
282
- return await resolveCallback(resolved, HtmlEscapedCallbackPhase.Stringify, false, {});
298
+ const resolved = value instanceof Promise ? await value : value;
299
+ if (typeof resolved === "string") return resolved;
300
+ if (resolved === null || resolved === void 0 || typeof resolved === "boolean") return "";
301
+ if (typeof resolved === "number") return String(resolved);
302
+ return await resolveCallback(resolved, HtmlEscapedCallbackPhase.Stringify, false, {});
283
303
  }
284
304
  function isJsxValue(value) {
285
- return typeof value === "object" && value !== null && "tag" in value && "props" in value && "type" in value;
305
+ return typeof value === "object" && value !== null && "tag" in value && "props" in value && "type" in value;
286
306
  }
287
-
288
- // src/renderer/control-icons.ts
289
- import { jsx as jsx2 } from "hono/jsx/jsx-runtime";
307
+ //#endregion
308
+ //#region src/renderer/control-icons.ts
290
309
  function renderControlIcon(name, className = "hono-decks-control-icon") {
291
- return jsx2("svg", {
292
- class: className,
293
- "data-hono-decks-control-icon": true,
294
- viewBox: "0 0 24 24",
295
- "aria-hidden": "true",
296
- focusable: "false",
297
- fill: "none",
298
- "stroke-width": "2",
299
- "stroke-linecap": "round",
300
- "stroke-linejoin": "round",
301
- children: controlIconPaths(name)
302
- });
310
+ return jsx("svg", {
311
+ class: className,
312
+ "data-hono-decks-control-icon": true,
313
+ viewBox: "0 0 24 24",
314
+ "aria-hidden": "true",
315
+ focusable: "false",
316
+ fill: "none",
317
+ "stroke-width": "2",
318
+ "stroke-linecap": "round",
319
+ "stroke-linejoin": "round",
320
+ children: controlIconPaths(name)
321
+ });
303
322
  }
304
323
  function controlIconLabel(name) {
305
- switch (name) {
306
- case "deck-list":
307
- return "Deck list";
308
- case "home":
309
- return "Home";
310
- case "viewer":
311
- return "Viewer";
312
- case "projection":
313
- return "Projection";
314
- case "presenter":
315
- return "Presenter";
316
- case "previous":
317
- return "Previous slide";
318
- case "next":
319
- return "Next slide";
320
- case "fullscreen":
321
- return "Toggle fullscreen";
322
- case "print":
323
- return "Print view";
324
- case "details":
325
- return "Details";
326
- case "export-pdf":
327
- return "Export PDF";
328
- case "export-png":
329
- return "Export PNG";
330
- }
324
+ switch (name) {
325
+ case "deck-list": return "Deck list";
326
+ case "home": return "Home";
327
+ case "viewer": return "Viewer";
328
+ case "projection": return "Projection";
329
+ case "presenter": return "Presenter";
330
+ case "previous": return "Previous slide";
331
+ case "next": return "Next slide";
332
+ case "fullscreen": return "Toggle fullscreen";
333
+ case "print": return "Print view";
334
+ case "details": return "Details";
335
+ case "export-pdf": return "Export PDF";
336
+ case "export-png": return "Export PNG";
337
+ }
331
338
  }
332
339
  function controlIconPaths(name) {
333
- switch (name) {
334
- case "deck-list":
335
- return [
336
- jsx2("path", { d: "M4 5h16" }),
337
- jsx2("path", { d: "M4 12h16" }),
338
- jsx2("path", { d: "M4 19h16" })
339
- ];
340
- case "home":
341
- return [
342
- jsx2("path", { d: "M3 11l9-8 9 8" }),
343
- jsx2("path", { d: "M5 10v10h14V10" }),
344
- jsx2("path", { d: "M9 20v-6h6v6" })
345
- ];
346
- case "viewer":
347
- return [
348
- jsx2("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z" }),
349
- jsx2("circle", { cx: "12", cy: "12", r: "3" })
350
- ];
351
- case "projection":
352
- return [
353
- jsx2("path", { d: "M4 5h16v10H4z" }),
354
- jsx2("path", { d: "M8 19h8" }),
355
- jsx2("path", { d: "M12 15v4" })
356
- ];
357
- case "presenter":
358
- return [
359
- jsx2("path", { d: "M4 5h16v10H4z" }),
360
- jsx2("path", { d: "M8 21l4-6 4 6" }),
361
- jsx2("path", { d: "M9 9h6" })
362
- ];
363
- case "previous":
364
- return [jsx2("path", { d: "M15 6l-6 6 6 6" })];
365
- case "next":
366
- return [jsx2("path", { d: "M9 6l6 6-6 6" })];
367
- case "fullscreen":
368
- return [
369
- jsx2("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
370
- jsx2("path", { d: "M16 3h3a2 2 0 0 1 2 2v3" }),
371
- jsx2("path", { d: "M8 21H5a2 2 0 0 1-2-2v-3" }),
372
- jsx2("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
373
- ];
374
- case "print":
375
- return [
376
- jsx2("path", { d: "M6 9V3h12v6" }),
377
- jsx2("path", { d: "M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2" }),
378
- jsx2("path", { d: "M6 14h12v7H6z" })
379
- ];
380
- case "details":
381
- return [
382
- jsx2("circle", { cx: "12", cy: "12", r: "9" }),
383
- jsx2("path", { d: "M12 11v5" }),
384
- jsx2("path", { d: "M12 8h.01" })
385
- ];
386
- case "export-pdf":
387
- return [
388
- jsx2("path", { d: "M14 3v4a2 2 0 0 0 2 2h4" }),
389
- jsx2("path", { d: "M5 3h9l6 6v12H5z" }),
390
- jsx2("path", { d: "M8 15h8" }),
391
- jsx2("path", { d: "M8 18h5" })
392
- ];
393
- case "export-png":
394
- return [
395
- jsx2("rect", { x: "4", y: "5", width: "16", height: "14", rx: "2" }),
396
- jsx2("path", { d: "M8 14l2.5-2.5L14 15l2-2 2 2" }),
397
- jsx2("circle", { cx: "9", cy: "9", r: "1" })
398
- ];
399
- }
340
+ switch (name) {
341
+ case "deck-list": return [
342
+ jsx("path", { d: "M4 5h16" }),
343
+ jsx("path", { d: "M4 12h16" }),
344
+ jsx("path", { d: "M4 19h16" })
345
+ ];
346
+ case "home": return [
347
+ jsx("path", { d: "M3 11l9-8 9 8" }),
348
+ jsx("path", { d: "M5 10v10h14V10" }),
349
+ jsx("path", { d: "M9 20v-6h6v6" })
350
+ ];
351
+ case "viewer": return [jsx("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z" }), jsx("circle", {
352
+ cx: "12",
353
+ cy: "12",
354
+ r: "3"
355
+ })];
356
+ case "projection": return [
357
+ jsx("path", { d: "M4 5h16v10H4z" }),
358
+ jsx("path", { d: "M8 19h8" }),
359
+ jsx("path", { d: "M12 15v4" })
360
+ ];
361
+ case "presenter": return [
362
+ jsx("path", { d: "M4 5h16v10H4z" }),
363
+ jsx("path", { d: "M8 21l4-6 4 6" }),
364
+ jsx("path", { d: "M9 9h6" })
365
+ ];
366
+ case "previous": return [jsx("path", { d: "M15 6l-6 6 6 6" })];
367
+ case "next": return [jsx("path", { d: "M9 6l6 6-6 6" })];
368
+ case "fullscreen": return [
369
+ jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
370
+ jsx("path", { d: "M16 3h3a2 2 0 0 1 2 2v3" }),
371
+ jsx("path", { d: "M8 21H5a2 2 0 0 1-2-2v-3" }),
372
+ jsx("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
373
+ ];
374
+ case "print": return [
375
+ jsx("path", { d: "M6 9V3h12v6" }),
376
+ jsx("path", { d: "M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2" }),
377
+ jsx("path", { d: "M6 14h12v7H6z" })
378
+ ];
379
+ case "details": return [
380
+ jsx("circle", {
381
+ cx: "12",
382
+ cy: "12",
383
+ r: "9"
384
+ }),
385
+ jsx("path", { d: "M12 11v5" }),
386
+ jsx("path", { d: "M12 8h.01" })
387
+ ];
388
+ case "export-pdf": return [
389
+ jsx("path", { d: "M14 3v4a2 2 0 0 0 2 2h4" }),
390
+ jsx("path", { d: "M5 3h9l6 6v12H5z" }),
391
+ jsx("path", { d: "M8 15h8" }),
392
+ jsx("path", { d: "M8 18h5" })
393
+ ];
394
+ case "export-png": return [
395
+ jsx("rect", {
396
+ x: "4",
397
+ y: "5",
398
+ width: "16",
399
+ height: "14",
400
+ rx: "2"
401
+ }),
402
+ jsx("path", { d: "M8 14l2.5-2.5L14 15l2-2 2 2" }),
403
+ jsx("circle", {
404
+ cx: "9",
405
+ cy: "9",
406
+ r: "1"
407
+ })
408
+ ];
409
+ }
400
410
  }
401
-
402
- // src/server/paths.ts
411
+ //#endregion
412
+ //#region src/server/paths.ts
413
+ /** Creates the canonical route map used by routers, controls, and app code. */
403
414
  function createDeckPaths(mountPath, slug) {
404
- const mount = normalizeMountPath(mountPath);
405
- const viewer = `${mount === "/" ? "" : mount}/${encodeURIComponent(slug)}`;
406
- return {
407
- viewer,
408
- render: `${viewer}/render`,
409
- print: `${viewer}/print`,
410
- presentation: `${viewer}/presentation`,
411
- presenter: `${viewer}/presenter`,
412
- embed: `${viewer}/embed`,
413
- exportPdf: `${viewer}/export.pdf`,
414
- exportPng: `${viewer}/export.png`,
415
- ogImage: `${viewer}/og.png`,
416
- assets: `${viewer}/assets`
417
- };
415
+ const mount = normalizeMountPath(mountPath);
416
+ const viewer = `${mount === "/" ? "" : mount}/${encodeURIComponent(slug)}`;
417
+ return {
418
+ viewer,
419
+ render: `${viewer}/render`,
420
+ print: `${viewer}/print`,
421
+ presentation: `${viewer}/presentation`,
422
+ presenter: `${viewer}/presenter`,
423
+ embed: `${viewer}/embed`,
424
+ exportPdf: `${viewer}/export.pdf`,
425
+ exportPng: `${viewer}/export.png`,
426
+ ogImage: `${viewer}/og.png`,
427
+ assets: `${viewer}/assets`
428
+ };
418
429
  }
430
+ /** Normalizes a configured mount path to one leading slash and no trailing slash. */
419
431
  function normalizeMountPath(value) {
420
- const trimmed = value.trim();
421
- if (!trimmed || trimmed === "/") return "/";
422
- return `/${trimmed.replace(/^\/+|\/+$/g, "")}`;
432
+ const trimmed = value.trim();
433
+ if (!trimmed || trimmed === "/") return "/";
434
+ let start = 0;
435
+ let end = trimmed.length;
436
+ while (trimmed[start] === "/") start += 1;
437
+ while (end > start && trimmed[end - 1] === "/") end -= 1;
438
+ return `/${trimmed.slice(start, end)}`;
423
439
  }
424
-
425
- // src/server/viewer.ts
426
- import { raw } from "hono/html";
427
- import { jsx as jsx3 } from "hono/jsx/jsx-runtime";
428
-
429
- // src/server/viewer-script.ts
430
- var VIEWER_STATE_MESSAGE_TYPE = "hono-decks:state";
431
- var VIEWER_COMMAND_MESSAGE_TYPE = "hono-decks:command";
440
+ //#endregion
441
+ //#region src/server/viewer-script.ts
442
+ const VIEWER_STATE_MESSAGE_TYPE = "hono-decks:state";
443
+ const VIEWER_COMMAND_MESSAGE_TYPE = "hono-decks:command";
432
444
  function renderViewerScript(nonce) {
433
- const nonceAttribute = nonce ? ` nonce="${escapeHtml(nonce)}"` : "";
434
- return `<script data-hono-decks-viewer-runtime${nonceAttribute}>
445
+ return `<script data-hono-decks-viewer-runtime${nonce ? ` nonce="${escapeHtml$1(nonce)}"` : ""}>
435
446
  (() => {
436
447
  const roots = Array.from(document.querySelectorAll("[data-hono-decks-viewer]"));
437
448
  const runtime = window.__honoDecksViewerRuntime ??= { controllers: new Map(), globalInitialized: false };
@@ -618,17 +629,17 @@ function renderViewerScript(nonce) {
618
629
  });
619
630
  }
620
631
  })();
621
- </script>`;
632
+ <\/script>`;
622
633
  }
623
- function escapeHtml(value) {
624
- return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
634
+ function escapeHtml$1(value) {
635
+ return value.replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
625
636
  }
626
-
627
- // src/server/viewer-style.ts
628
- var VIEWER_ASPECT_RATIO = "16/9";
637
+ //#endregion
638
+ //#region src/server/viewer-style.ts
639
+ const VIEWER_ASPECT_RATIO = "16/9";
629
640
  function embeddedViewerStyle() {
630
- const root = "[data-hono-decks-viewer][data-hono-decks-embed]";
631
- return `${root}{color-scheme:dark;background:#050816;color:#eef2ff;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;display:grid;gap:12px;width:100%;min-width:0;box-sizing:border-box}
641
+ const root = "[data-hono-decks-viewer][data-hono-decks-embed]";
642
+ return `${root}{color-scheme:dark;background:#050816;color:#eef2ff;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;display:grid;gap:12px;width:100%;min-width:0;box-sizing:border-box}
632
643
  ${root} *:focus-visible{outline:none}
633
644
  ${root} .hono-decks-viewer-shell{display:grid;grid-template-rows:minmax(0,1fr) auto;place-items:center;width:100%;min-width:0;min-height:0;box-sizing:border-box}
634
645
  ${root} .hono-decks-viewer-stage{display:grid;place-items:center;width:100%;min-width:0;min-height:0;container-type:inline-size}
@@ -649,423 +660,465 @@ ${root} .hono-decks-control-icon{width:16px;height:16px;flex:0 0 auto;stroke:cur
649
660
  ${root} .hono-decks-viewer-toc button{font:inherit}
650
661
  @media (prefers-reduced-motion: reduce){${root},${root} *{scroll-behavior:auto!important;animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}}`;
651
662
  }
652
-
653
- // src/server/viewer.ts
663
+ //#endregion
664
+ //#region src/server/viewer.ts
654
665
  async function createDeckViewerParts(input) {
655
- const slug = input.deck.slug;
656
- const title = input.deck.meta.title ?? slug;
657
- const basePath = input.mountPath.replace(/\/$/, "");
658
- const paths = createDeckPaths(basePath, slug);
659
- const imagePath = await resolveOpenGraphImagePath(input.openGraph, { deck: input.deck, paths });
660
- const renderUrl = `${paths.render}${input.viewerStateQuery ?? ""}`;
661
- const slides = createDeckToc(input.deck);
662
- const meta = {
663
- title,
664
- description: input.deck.meta.description,
665
- paths,
666
- availablePages: { print: input.availablePages?.print !== false },
667
- availableExports: input.exportPaths ?? {},
668
- ...imagePath ? { imagePath } : {}
669
- };
670
- const controlsInput = input.controls === false ? false : input.controls ?? {};
671
- const controlsContext = { slug, title, mountPath: basePath, meta, slides };
672
- const controls = controlsInput === false ? null : renderViewerControls(controlsInput, controlsContext);
673
- return {
674
- slug,
675
- title,
676
- renderUrl,
677
- frame: {
678
- content: renderViewerFrame({ title, renderUrl }),
679
- html: renderViewerFrameHtml({ title, renderUrl })
680
- },
681
- controls: controls ? { content: controls, html: await renderJsxValue(controls) } : null,
682
- toc: { content: renderViewerToc(slides), html: renderViewerTocHtml(slides) },
683
- slides,
684
- meta
685
- };
666
+ const slug = input.deck.slug;
667
+ const title = input.deck.meta.title ?? slug;
668
+ const basePath = input.mountPath.replace(/\/$/, "");
669
+ const paths = createDeckPaths(basePath, slug);
670
+ const imagePath = await resolveOpenGraphImagePath(input.openGraph, {
671
+ deck: input.deck,
672
+ paths
673
+ });
674
+ const renderUrl = `${paths.render}${input.viewerStateQuery ?? ""}`;
675
+ const slides = createDeckToc(input.deck);
676
+ const meta = {
677
+ title,
678
+ description: input.deck.meta.description,
679
+ paths,
680
+ availablePages: { print: input.availablePages?.print !== false },
681
+ availableExports: input.exportPaths ?? {},
682
+ ...imagePath ? { imagePath } : {}
683
+ };
684
+ const controlsInput = input.controls === false ? false : input.controls ?? {};
685
+ const controls = controlsInput === false ? null : renderViewerControls(controlsInput, {
686
+ slug,
687
+ title,
688
+ mountPath: basePath,
689
+ meta,
690
+ slides
691
+ });
692
+ return {
693
+ slug,
694
+ title,
695
+ renderUrl,
696
+ frame: {
697
+ content: renderViewerFrame({
698
+ title,
699
+ renderUrl
700
+ }),
701
+ html: renderViewerFrameHtml({
702
+ title,
703
+ renderUrl
704
+ })
705
+ },
706
+ controls: controls ? {
707
+ content: controls,
708
+ html: await renderJsxValue(controls)
709
+ } : null,
710
+ toc: {
711
+ content: renderViewerToc(slides),
712
+ html: renderViewerTocHtml(slides)
713
+ },
714
+ slides,
715
+ meta
716
+ };
686
717
  }
687
718
  async function createDeckViewerEmbed(input) {
688
- const parts = await createDeckViewerParts(input);
689
- const root = jsx3("section", {
690
- class: ["hono-decks-embedded-viewer", input.className].filter(Boolean).join(" "),
691
- "data-hono-decks-viewer": true,
692
- "data-hono-decks-embed": true,
693
- "data-deck-slug": parts.slug,
694
- ...parts.meta.availablePages.print ? { "data-hono-decks-print-path": parts.meta.paths.print } : {},
695
- "aria-label": parts.title,
696
- children: [
697
- jsx3("div", {
698
- class: "hono-decks-viewer-shell",
699
- children: [parts.frame.content, parts.controls?.content]
700
- }),
701
- input.toc ? parts.toc.content : null
702
- ]
703
- });
704
- const rootHtml = await renderJsxValue(root);
705
- const nonceAttribute = input.nonce ? ` nonce="${escapeHtml2(input.nonce)}"` : "";
706
- const embedHtml = `<style data-hono-decks-embed-style${nonceAttribute}>${embeddedViewerStyle()}${input.style ?? ""}</style>${rootHtml}${renderViewerScript(input.nonce)}`;
707
- return {
708
- ...parts,
709
- embed: raw(embedHtml),
710
- embedHtml
711
- };
719
+ const parts = await createDeckViewerParts(input);
720
+ const rootHtml = await renderJsxValue(jsx("section", {
721
+ class: ["hono-decks-embedded-viewer", input.className].filter(Boolean).join(" "),
722
+ "data-hono-decks-viewer": true,
723
+ "data-hono-decks-embed": true,
724
+ "data-deck-slug": parts.slug,
725
+ ...parts.meta.availablePages.print ? { "data-hono-decks-print-path": parts.meta.paths.print } : {},
726
+ "aria-label": parts.title,
727
+ children: [jsx("div", {
728
+ class: "hono-decks-viewer-shell",
729
+ children: [parts.frame.content, parts.controls?.content]
730
+ }), input.toc ? parts.toc.content : null]
731
+ }));
732
+ const embedHtml = `<style data-hono-decks-embed-style${input.nonce ? ` nonce="${escapeHtml(input.nonce)}"` : ""}>${embeddedViewerStyle()}${input.style ?? ""}</style>${rootHtml}${renderViewerScript(input.nonce)}`;
733
+ return {
734
+ ...parts,
735
+ embed: raw(embedHtml),
736
+ embedHtml
737
+ };
712
738
  }
713
739
  async function resolveOpenGraphImagePath(options, input) {
714
- if (!options) return void 0;
715
- if (options === true) return input.paths.ogImage;
716
- if (typeof options.imagePath === "function") return options.imagePath(input);
717
- return options.imagePath ?? input.paths.ogImage;
740
+ if (!options) return void 0;
741
+ if (options === true) return input.paths.ogImage;
742
+ if (typeof options.imagePath === "function") return options.imagePath(input);
743
+ return options.imagePath ?? input.paths.ogImage;
718
744
  }
719
745
  function createDeckToc(deck) {
720
- return deck.slides.map((slide) => ({
721
- index: slide.index,
722
- title: slide.meta.title,
723
- label: slide.meta.title ?? `Slide ${slide.index + 1}`
724
- }));
746
+ return deck.slides.map((slide) => ({
747
+ index: slide.index,
748
+ title: slide.meta.title,
749
+ label: slide.meta.title ?? `Slide ${slide.index + 1}`
750
+ }));
725
751
  }
726
752
  function renderViewerFrame(input) {
727
- return jsx3("div", {
728
- class: "hono-decks-viewer-stage",
729
- "data-hono-decks-frame": true,
730
- children: jsx3("div", {
731
- class: "hono-decks-viewport",
732
- "data-viewer-viewport": true,
733
- tabindex: "0",
734
- children: [
735
- jsx3("div", {
736
- class: "hono-decks-frame-stage",
737
- "data-viewer-stage": true,
738
- children: jsx3("iframe", {
739
- title: input.title,
740
- src: input.renderUrl
741
- })
742
- }),
743
- jsx3("button", {
744
- class: "hono-decks-viewer-navigation-layer hono-decks-viewer-navigation-previous",
745
- type: "button",
746
- "data-viewer-navigation": "previous",
747
- "aria-label": "Previous slide"
748
- }),
749
- jsx3("button", {
750
- class: "hono-decks-viewer-navigation-layer hono-decks-viewer-navigation-next",
751
- type: "button",
752
- "data-viewer-navigation": "next",
753
- "aria-label": "Next slide"
754
- })
755
- ]
756
- })
757
- });
753
+ return jsx("div", {
754
+ class: "hono-decks-viewer-stage",
755
+ "data-hono-decks-frame": true,
756
+ children: jsx("div", {
757
+ class: "hono-decks-viewport",
758
+ "data-viewer-viewport": true,
759
+ tabindex: "0",
760
+ children: [
761
+ jsx("div", {
762
+ class: "hono-decks-frame-stage",
763
+ "data-viewer-stage": true,
764
+ children: jsx("iframe", {
765
+ title: input.title,
766
+ src: input.renderUrl
767
+ })
768
+ }),
769
+ jsx("button", {
770
+ class: "hono-decks-viewer-navigation-layer hono-decks-viewer-navigation-previous",
771
+ type: "button",
772
+ "data-viewer-navigation": "previous",
773
+ "aria-label": "Previous slide"
774
+ }),
775
+ jsx("button", {
776
+ class: "hono-decks-viewer-navigation-layer hono-decks-viewer-navigation-next",
777
+ type: "button",
778
+ "data-viewer-navigation": "next",
779
+ "aria-label": "Next slide"
780
+ })
781
+ ]
782
+ })
783
+ });
758
784
  }
759
785
  function renderViewerFrameHtml(input) {
760
- return `<div class="hono-decks-viewer-stage" data-hono-decks-frame><div class="hono-decks-viewport" data-viewer-viewport tabindex="0"><div class="hono-decks-frame-stage" data-viewer-stage><iframe title="${escapeHtml2(input.title)}" src="${escapeHtml2(input.renderUrl)}"></iframe></div><button class="hono-decks-viewer-navigation-layer hono-decks-viewer-navigation-previous" type="button" data-viewer-navigation="previous" aria-label="Previous slide"></button><button class="hono-decks-viewer-navigation-layer hono-decks-viewer-navigation-next" type="button" data-viewer-navigation="next" aria-label="Next slide"></button></div></div>`;
786
+ return `<div class="hono-decks-viewer-stage" data-hono-decks-frame><div class="hono-decks-viewport" data-viewer-viewport tabindex="0"><div class="hono-decks-frame-stage" data-viewer-stage><iframe title="${escapeHtml(input.title)}" src="${escapeHtml(input.renderUrl)}"></iframe></div><button class="hono-decks-viewer-navigation-layer hono-decks-viewer-navigation-previous" type="button" data-viewer-navigation="previous" aria-label="Previous slide"></button><button class="hono-decks-viewer-navigation-layer hono-decks-viewer-navigation-next" type="button" data-viewer-navigation="next" aria-label="Next slide"></button></div></div>`;
761
787
  }
762
788
  function renderViewerControls(options, context) {
763
- return jsx3("nav", {
764
- ...controlAttributes(options.attributes),
765
- class: controlsClassName(options),
766
- "data-hono-decks-viewer-controls": true,
767
- "aria-label": options.ariaLabel ?? "Viewer controls",
768
- children: resolveViewerControlItems(options, context).map((item) => renderViewerControlItem(item, options, context))
769
- });
789
+ return jsx("nav", {
790
+ ...controlAttributes(options.attributes),
791
+ class: controlsClassName(options),
792
+ "data-hono-decks-viewer-controls": true,
793
+ "aria-label": options.ariaLabel ?? "Viewer controls",
794
+ children: resolveViewerControlItems(options, context).map((item) => renderViewerControlItem(item, options, context))
795
+ });
770
796
  }
771
797
  function renderViewerToc(slides) {
772
- return jsx3("nav", {
773
- class: "hono-decks-viewer-toc",
774
- "data-hono-decks-toc": true,
775
- "aria-label": "Slide navigation",
776
- children: jsx3("ol", {
777
- children: slides.map(
778
- (slide) => jsx3("li", {
779
- children: jsx3("button", {
780
- type: "button",
781
- "data-action": "goTo",
782
- "data-slide-index": String(slide.index),
783
- children: slide.label
784
- })
785
- })
786
- )
787
- })
788
- });
798
+ return jsx("nav", {
799
+ class: "hono-decks-viewer-toc",
800
+ "data-hono-decks-toc": true,
801
+ "aria-label": "Slide navigation",
802
+ children: jsx("ol", { children: slides.map((slide) => jsx("li", { children: jsx("button", {
803
+ type: "button",
804
+ "data-action": "goTo",
805
+ "data-slide-index": String(slide.index),
806
+ children: slide.label
807
+ }) })) })
808
+ });
789
809
  }
790
810
  function renderViewerTocHtml(slides) {
791
- const items = slides.map(
792
- (slide) => `<li><button type="button" data-action="goTo" data-slide-index="${slide.index}">${escapeHtml2(slide.label)}</button></li>`
793
- ).join("");
794
- return `<nav class="hono-decks-viewer-toc" data-hono-decks-toc aria-label="Slide navigation"><ol>${items}</ol></nav>`;
811
+ return `<nav class="hono-decks-viewer-toc" data-hono-decks-toc aria-label="Slide navigation"><ol>${slides.map((slide) => `<li><button type="button" data-action="goTo" data-slide-index="${slide.index}">${escapeHtml(slide.label)}</button></li>`).join("")}</ol></nav>`;
795
812
  }
796
- function escapeHtml2(value) {
797
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
813
+ function escapeHtml(value) {
814
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
798
815
  }
799
816
  function safeFilename(value) {
800
- const normalized = value.trim().replaceAll(/[^a-zA-Z0-9._-]+/g, "-").replaceAll(/^-+|-+$/g, "");
801
- return normalized || "deck";
817
+ return value.trim().replaceAll(/[^a-zA-Z0-9._-]+/g, "-").replaceAll(/^-+|-+$/g, "") || "deck";
802
818
  }
803
819
  function buildViewerControlDefaults(context) {
804
- return {
805
- back: { type: "default", key: "back" },
806
- previous: { type: "default", key: "previous" },
807
- position: { type: "default", key: "position" },
808
- next: { type: "default", key: "next" },
809
- fullscreen: { type: "default", key: "fullscreen" },
810
- print: context.meta.availablePages.print ? { type: "default", key: "print" } : null,
811
- exportPdf: context.meta.availableExports.pdf ? { type: "default", key: "exportPdf" } : null,
812
- exportPng: context.meta.availableExports.png ? { type: "default", key: "exportPng" } : null
813
- };
820
+ return {
821
+ back: {
822
+ type: "default",
823
+ key: "back"
824
+ },
825
+ previous: {
826
+ type: "default",
827
+ key: "previous"
828
+ },
829
+ position: {
830
+ type: "default",
831
+ key: "position"
832
+ },
833
+ next: {
834
+ type: "default",
835
+ key: "next"
836
+ },
837
+ fullscreen: {
838
+ type: "default",
839
+ key: "fullscreen"
840
+ },
841
+ print: context.meta.availablePages.print ? {
842
+ type: "default",
843
+ key: "print"
844
+ } : null,
845
+ exportPdf: context.meta.availableExports.pdf ? {
846
+ type: "default",
847
+ key: "exportPdf"
848
+ } : null,
849
+ exportPng: context.meta.availableExports.png ? {
850
+ type: "default",
851
+ key: "exportPng"
852
+ } : null
853
+ };
814
854
  }
815
855
  function resolveViewerControlItems(options, context) {
816
- const defaults = buildViewerControlDefaults(context);
817
- const baseItems = [
818
- defaults.back,
819
- defaults.previous,
820
- defaults.position,
821
- defaults.next,
822
- defaults.fullscreen,
823
- defaults.print,
824
- defaults.exportPdf,
825
- defaults.exportPng
826
- ];
827
- const items = typeof options.items === "function" ? options.items(defaults, context) : options.items ?? [
828
- ...resolveViewerControlSlotItems(options.before, context),
829
- ...filterHiddenDefaultItems(baseItems, options.hidden),
830
- ...resolveViewerControlSlotItems(options.after, context)
831
- ];
832
- return items.filter((item) => Boolean(item)).map((item) => applyViewerControlLabels(item, options.labels));
856
+ const defaults = buildViewerControlDefaults(context);
857
+ const baseItems = [
858
+ defaults.back,
859
+ defaults.previous,
860
+ defaults.position,
861
+ defaults.next,
862
+ defaults.fullscreen,
863
+ defaults.print,
864
+ defaults.exportPdf,
865
+ defaults.exportPng
866
+ ];
867
+ return (typeof options.items === "function" ? options.items(defaults, context) : options.items ?? [
868
+ ...resolveViewerControlSlotItems(options.before, context),
869
+ ...filterHiddenDefaultItems(baseItems, options.hidden),
870
+ ...resolveViewerControlSlotItems(options.after, context)
871
+ ]).filter((item) => Boolean(item)).map((item) => applyViewerControlLabels(item, options.labels));
833
872
  }
834
873
  function renderViewerControlItem(item, options, context) {
835
- const renderDefault = () => renderBaseViewerControlItem(item, options, context);
836
- return options.renderItem?.(item, context, renderDefault) ?? renderDefault();
874
+ const renderDefault = () => renderBaseViewerControlItem(item, options, context);
875
+ return options.renderItem?.(item, context, renderDefault) ?? renderDefault();
837
876
  }
838
877
  function renderBaseViewerControlItem(item, options, context) {
839
- if (item.type === "link") {
840
- const ariaLabel = item.icon ? String(item.attributes?.["aria-label"] ?? item.label) : void 0;
841
- return jsx3("a", {
842
- ...linkAttributes(item.attributes),
843
- ...safeHref(item.href) ? { href: safeHref(item.href) } : {},
844
- ...item.download ? { download: item.download } : {},
845
- ...classAttribute(options.itemClassName, item.className),
846
- ...item.icon ? { "aria-label": ariaLabel, title: ariaLabel } : {},
847
- children: item.icon ? renderControlIcon(item.icon) : item.label
848
- });
849
- }
850
- if (item.type === "render") {
851
- return item.render({ context });
852
- }
853
- return renderDefaultViewerControlItem(item, options, context);
878
+ if (item.type === "link") {
879
+ const ariaLabel = item.icon ? String(item.attributes?.["aria-label"] ?? item.label) : void 0;
880
+ return jsx("a", {
881
+ ...linkAttributes(item.attributes),
882
+ ...safeHref(item.href) ? { href: safeHref(item.href) } : {},
883
+ ...item.download ? { download: item.download } : {},
884
+ ...classAttribute(options.itemClassName, item.className),
885
+ ...item.icon ? {
886
+ "aria-label": ariaLabel,
887
+ title: ariaLabel
888
+ } : {},
889
+ children: item.icon ? renderControlIcon(item.icon) : item.label
890
+ });
891
+ }
892
+ if (item.type === "render") return item.render({ context });
893
+ return renderDefaultViewerControlItem(item, options, context);
854
894
  }
855
895
  function renderDefaultViewerControlItem(item, options, context) {
856
- const itemProps = {
857
- ...linkAttributes(item.attributes),
858
- ...classAttribute(options.itemClassName, item.className)
859
- };
860
- switch (item.key) {
861
- case "back":
862
- return jsx3("a", {
863
- ...itemProps,
864
- href: context.mountPath,
865
- "data-hono-decks-back-link": true,
866
- ...item.label === void 0 ? { "aria-label": controlIconLabel("deck-list"), title: controlIconLabel("deck-list") } : {},
867
- children: item.label ?? renderControlIcon("deck-list")
868
- });
869
- case "previous":
870
- return renderIconButton("previous", item, itemProps);
871
- case "position":
872
- return jsx3("span", {
873
- ...itemProps,
874
- "data-slide-position": true,
875
- "data-hono-decks-position": true,
876
- children: item.label ?? "1 / ?"
877
- });
878
- case "next":
879
- return renderIconButton("next", item, itemProps);
880
- case "fullscreen":
881
- return renderIconButton("fullscreen", item, itemProps);
882
- case "print":
883
- return jsx3("a", {
884
- ...itemProps,
885
- href: context.meta.paths.print,
886
- "data-hono-decks-print": true,
887
- ...item.label === void 0 ? { "aria-label": controlIconLabel("print"), title: controlIconLabel("print") } : {},
888
- children: item.label ?? renderControlIcon("print")
889
- });
890
- case "exportPdf":
891
- return jsx3("a", {
892
- ...itemProps,
893
- href: context.meta.paths.exportPdf,
894
- download: `${safeFilename(context.meta.title)}.pdf`,
895
- "data-hono-decks-export": "pdf",
896
- ...item.label === void 0 ? { "aria-label": controlIconLabel("export-pdf"), title: controlIconLabel("export-pdf") } : {},
897
- children: item.label ?? renderControlIcon("export-pdf")
898
- });
899
- case "exportPng":
900
- return jsx3("a", {
901
- ...itemProps,
902
- href: context.meta.paths.exportPng,
903
- download: `${safeFilename(context.meta.title)}.png`,
904
- "data-hono-decks-export": "png",
905
- ...item.label === void 0 ? { "aria-label": controlIconLabel("export-png"), title: controlIconLabel("export-png") } : {},
906
- children: item.label ?? renderControlIcon("export-png")
907
- });
908
- }
896
+ const itemProps = {
897
+ ...linkAttributes(item.attributes),
898
+ ...classAttribute(options.itemClassName, item.className)
899
+ };
900
+ switch (item.key) {
901
+ case "back": return jsx("a", {
902
+ ...itemProps,
903
+ href: context.mountPath,
904
+ "data-hono-decks-back-link": true,
905
+ ...item.label === void 0 ? {
906
+ "aria-label": controlIconLabel("deck-list"),
907
+ title: controlIconLabel("deck-list")
908
+ } : {},
909
+ children: item.label ?? renderControlIcon("deck-list")
910
+ });
911
+ case "previous": return renderIconButton("previous", item, itemProps);
912
+ case "position": return jsx("span", {
913
+ ...itemProps,
914
+ "data-slide-position": true,
915
+ "data-hono-decks-position": true,
916
+ children: item.label ?? "1 / ?"
917
+ });
918
+ case "next": return renderIconButton("next", item, itemProps);
919
+ case "fullscreen": return renderIconButton("fullscreen", item, itemProps);
920
+ case "print": return jsx("a", {
921
+ ...itemProps,
922
+ href: context.meta.paths.print,
923
+ "data-hono-decks-print": true,
924
+ ...item.label === void 0 ? {
925
+ "aria-label": controlIconLabel("print"),
926
+ title: controlIconLabel("print")
927
+ } : {},
928
+ children: item.label ?? renderControlIcon("print")
929
+ });
930
+ case "exportPdf": return jsx("a", {
931
+ ...itemProps,
932
+ href: context.meta.paths.exportPdf,
933
+ download: `${safeFilename(context.meta.title)}.pdf`,
934
+ "data-hono-decks-export": "pdf",
935
+ ...item.label === void 0 ? {
936
+ "aria-label": controlIconLabel("export-pdf"),
937
+ title: controlIconLabel("export-pdf")
938
+ } : {},
939
+ children: item.label ?? renderControlIcon("export-pdf")
940
+ });
941
+ case "exportPng": return jsx("a", {
942
+ ...itemProps,
943
+ href: context.meta.paths.exportPng,
944
+ download: `${safeFilename(context.meta.title)}.png`,
945
+ "data-hono-decks-export": "png",
946
+ ...item.label === void 0 ? {
947
+ "aria-label": controlIconLabel("export-png"),
948
+ title: controlIconLabel("export-png")
949
+ } : {},
950
+ children: item.label ?? renderControlIcon("export-png")
951
+ });
952
+ }
909
953
  }
910
954
  function renderIconButton(action, item, itemProps) {
911
- const iconName = controlIconNameForKey(action);
912
- const label = controlIconLabel(iconName);
913
- return jsx3("button", {
914
- ...itemProps,
915
- type: "button",
916
- "data-action": action,
917
- "data-hono-decks-navigation-control": action,
918
- ...item.label === void 0 ? { "aria-label": label, title: label } : {},
919
- children: item.label ?? renderControlIcon(iconName)
920
- });
955
+ const iconName = controlIconNameForKey(action);
956
+ const label = controlIconLabel(iconName);
957
+ return jsx("button", {
958
+ ...itemProps,
959
+ type: "button",
960
+ "data-action": action,
961
+ "data-hono-decks-navigation-control": action,
962
+ ...item.label === void 0 ? {
963
+ "aria-label": label,
964
+ title: label
965
+ } : {},
966
+ children: item.label ?? renderControlIcon(iconName)
967
+ });
921
968
  }
922
969
  function controlIconNameForKey(key) {
923
- switch (key) {
924
- case "back":
925
- return "deck-list";
926
- case "previous":
927
- return "previous";
928
- case "next":
929
- return "next";
930
- case "fullscreen":
931
- return "fullscreen";
932
- case "print":
933
- return "print";
934
- case "exportPdf":
935
- return "export-pdf";
936
- case "exportPng":
937
- return "export-png";
938
- case "position":
939
- return "viewer";
940
- }
970
+ switch (key) {
971
+ case "back": return "deck-list";
972
+ case "previous": return "previous";
973
+ case "next": return "next";
974
+ case "fullscreen": return "fullscreen";
975
+ case "print": return "print";
976
+ case "exportPdf": return "export-pdf";
977
+ case "exportPng": return "export-png";
978
+ case "position": return "viewer";
979
+ }
941
980
  }
942
981
  function controlsClassName(options) {
943
- return ["hono-decks-viewer-controls", options.className].filter(Boolean).join(" ");
982
+ return ["hono-decks-viewer-controls", options.className].filter(Boolean).join(" ");
944
983
  }
945
984
  function resolveViewerControlSlotItems(items, context) {
946
- return typeof items === "function" ? items(context) : items ?? [];
985
+ return typeof items === "function" ? items(context) : items ?? [];
947
986
  }
948
987
  function filterHiddenDefaultItems(items, hidden) {
949
- if (!hidden?.length) return items;
950
- const hiddenKeys = new Set(hidden);
951
- return items.filter((item) => !item || item.type !== "default" || !hiddenKeys.has(item.key));
988
+ if (!hidden?.length) return items;
989
+ const hiddenKeys = new Set(hidden);
990
+ return items.filter((item) => !item || item.type !== "default" || !hiddenKeys.has(item.key));
952
991
  }
953
992
  function applyViewerControlLabels(item, labels) {
954
- if (item.type !== "default" || item.label !== void 0) return item;
955
- const label = labels?.[item.key];
956
- return label === void 0 ? item : { ...item, label };
993
+ if (item.type !== "default" || item.label !== void 0) return item;
994
+ const label = labels?.[item.key];
995
+ return label === void 0 ? item : {
996
+ ...item,
997
+ label
998
+ };
957
999
  }
958
1000
  function linkAttributes(attributes) {
959
- const props = {};
960
- for (const [name, value] of Object.entries(attributes ?? {})) {
961
- if (!isSafeAttributeName(name) || value === false || value === void 0) continue;
962
- props[name] = value;
963
- }
964
- return props;
1001
+ const props = {};
1002
+ for (const [name, value] of Object.entries(attributes ?? {})) {
1003
+ if (!isSafeAttributeName(name) || value === false || value === void 0) continue;
1004
+ props[name] = value;
1005
+ }
1006
+ return props;
965
1007
  }
966
1008
  function controlAttributes(attributes) {
967
- const props = linkAttributes(attributes);
968
- delete props.class;
969
- delete props["aria-label"];
970
- delete props["data-hono-decks-viewer-controls"];
971
- return props;
1009
+ const props = linkAttributes(attributes);
1010
+ delete props.class;
1011
+ delete props["aria-label"];
1012
+ delete props["data-hono-decks-viewer-controls"];
1013
+ return props;
972
1014
  }
973
1015
  function classAttribute(...classNames) {
974
- const className = classNames.filter(Boolean).join(" ");
975
- return className ? { class: className } : {};
1016
+ const className = classNames.filter(Boolean).join(" ");
1017
+ return className ? { class: className } : {};
976
1018
  }
977
1019
  function isSafeAttributeName(value) {
978
- return /^[A-Za-z_:][A-Za-z0-9:_.-]*$/.test(value) && !/^on/i.test(value);
1020
+ return /^[A-Za-z_:][A-Za-z0-9:_.-]*$/.test(value) && !/^on/i.test(value);
979
1021
  }
980
1022
  function safeHref(value) {
981
- const trimmed = value.trim();
982
- if (trimmed.length === 0) return void 0;
983
- if (/^(https?:|mailto:|tel:)/i.test(trimmed)) return value;
984
- if (/^(javascript:|data:|vbscript:)/i.test(trimmed)) return void 0;
985
- if (/^[^/?#.]+:/i.test(trimmed)) return void 0;
986
- return value;
1023
+ const trimmed = value.trim();
1024
+ if (trimmed.length === 0) return void 0;
1025
+ if (/^(https?:|mailto:|tel:)/i.test(trimmed)) return value;
1026
+ if (/^(javascript:|data:|vbscript:)/i.test(trimmed)) return void 0;
1027
+ if (/^[^/?#.]+:/i.test(trimmed)) return void 0;
1028
+ return value;
987
1029
  }
988
-
989
- // src/server/define-decks.ts
1030
+ //#endregion
1031
+ //#region src/server/define-decks.ts
1032
+ /** Defines the single configuration consumed by the CLI and runtime. */
990
1033
  function defineDecksConfig(config) {
991
- return config;
1034
+ return config;
992
1035
  }
993
-
994
- // src/source/r2-assets.ts
1036
+ //#endregion
1037
+ //#region src/source/r2-assets.ts
995
1038
  function withR2Assets(source, options) {
996
- return {
997
- async listDecks(c) {
998
- return source.listDecks(c);
999
- },
1000
- async getCompiledDeck(c, slug) {
1001
- return source.getCompiledDeck(c, slug);
1002
- },
1003
- async getAsset(c, slug, assetPath) {
1004
- const deck = await source.getCompiledDeck(c, slug);
1005
- const asset = deck ? findRoutableAsset(deck.assets, slug, assetPath) : void 0;
1006
- const bucket = asset ? await resolveBucket(options.bucket, c) : void 0;
1007
- if (deck && asset && bucket) {
1008
- const object = await bucket.get(resolveR2Key({ deck, asset, slug, assetPath }, options));
1009
- if (object) {
1010
- const response = await responseFromR2Object(object, { deck, asset, slug, assetPath }, options);
1011
- if (response) return response;
1012
- }
1013
- }
1014
- return source.getAsset?.(c, slug, assetPath) ?? null;
1015
- }
1016
- };
1039
+ return {
1040
+ async listDecks(c) {
1041
+ return source.listDecks(c);
1042
+ },
1043
+ async getCompiledDeck(c, slug) {
1044
+ return source.getCompiledDeck(c, slug);
1045
+ },
1046
+ async getAsset(c, slug, assetPath) {
1047
+ const deck = await source.getCompiledDeck(c, slug);
1048
+ const asset = deck ? findRoutableAsset(deck.assets, slug, assetPath) : void 0;
1049
+ const bucket = asset ? await resolveBucket(options.bucket, c) : void 0;
1050
+ if (deck && asset && bucket) {
1051
+ const object = await bucket.get(resolveR2Key({
1052
+ deck,
1053
+ asset,
1054
+ slug,
1055
+ assetPath
1056
+ }, options));
1057
+ if (object) {
1058
+ const response = await responseFromR2Object(object, {
1059
+ deck,
1060
+ asset,
1061
+ slug,
1062
+ assetPath
1063
+ }, options);
1064
+ if (response) return response;
1065
+ }
1066
+ }
1067
+ return source.getAsset?.(c, slug, assetPath) ?? null;
1068
+ }
1069
+ };
1017
1070
  }
1018
1071
  async function resolveBucket(bucket, c) {
1019
- return typeof bucket === "function" ? bucket(c) : bucket;
1072
+ return typeof bucket === "function" ? bucket(c) : bucket;
1020
1073
  }
1021
1074
  function findRoutableAsset(assets, slug, assetPath) {
1022
- const normalized = assetPath.replace(/^\/+/, "");
1023
- return assets.find((asset) => {
1024
- if (asset.type !== "local" && asset.type !== "r2") return false;
1025
- const suffix = `/${slug}/assets/${normalized}`;
1026
- return asset.publicPath.endsWith(suffix);
1027
- });
1075
+ const normalized = stripLeadingSlashes(assetPath);
1076
+ return assets.find((asset) => {
1077
+ if (asset.type !== "local" && asset.type !== "r2") return false;
1078
+ const suffix = `/${slug}/assets/${normalized}`;
1079
+ return asset.publicPath.endsWith(suffix);
1080
+ });
1028
1081
  }
1029
1082
  function resolveR2Key(input, options) {
1030
- if (options.key) return options.key(input);
1031
- if (input.asset.r2Key) return input.asset.r2Key;
1032
- const key = input.asset.sourcePath || `${input.slug}/assets/${input.assetPath}`;
1033
- const prefix = options.keyPrefix?.replace(/\/+$/, "");
1034
- return prefix ? `${prefix}/${key.replace(/^\/+/, "")}` : key.replace(/^\/+/, "");
1083
+ if (options.key) return options.key(input);
1084
+ if (input.asset.r2Key) return input.asset.r2Key;
1085
+ const key = input.asset.sourcePath || `${input.slug}/assets/${input.assetPath}`;
1086
+ const prefix = options.keyPrefix ? stripTrailingSlashes(options.keyPrefix) : void 0;
1087
+ const normalizedKey = stripLeadingSlashes(key);
1088
+ return prefix ? `${prefix}/${normalizedKey}` : normalizedKey;
1089
+ }
1090
+ function stripLeadingSlashes(value) {
1091
+ let index = 0;
1092
+ while (value[index] === "/") index += 1;
1093
+ return value.slice(index);
1094
+ }
1095
+ function stripTrailingSlashes(value) {
1096
+ let end = value.length;
1097
+ while (end > 0 && value[end - 1] === "/") end -= 1;
1098
+ return value.slice(0, end);
1035
1099
  }
1036
1100
  async function responseFromR2Object(object, input, options) {
1037
- const body = object.body ?? (object.arrayBuffer ? await object.arrayBuffer() : void 0);
1038
- if (body == null) return null;
1039
- const headers = new Headers();
1040
- object.writeHttpMetadata?.(headers);
1041
- applyHttpMetadata(headers, object.httpMetadata);
1042
- if (!headers.has("content-type") && input.asset.contentType) headers.set("content-type", input.asset.contentType);
1043
- const cacheControl = resolveCacheControl(input, options);
1044
- if (cacheControl) {
1045
- headers.set("cache-control", cacheControl);
1046
- } else if (cacheControl !== false && input.asset.cacheControl && !headers.has("cache-control")) {
1047
- headers.set("cache-control", input.asset.cacheControl);
1048
- }
1049
- return new Response(body, { headers });
1101
+ const body = object.body ?? (object.arrayBuffer ? await object.arrayBuffer() : void 0);
1102
+ if (body == null) return null;
1103
+ const headers = new Headers();
1104
+ object.writeHttpMetadata?.(headers);
1105
+ applyHttpMetadata(headers, object.httpMetadata);
1106
+ if (!headers.has("content-type") && input.asset.contentType) headers.set("content-type", input.asset.contentType);
1107
+ const cacheControl = resolveCacheControl(input, options);
1108
+ if (cacheControl) headers.set("cache-control", cacheControl);
1109
+ else if (cacheControl !== false && input.asset.cacheControl && !headers.has("cache-control")) headers.set("cache-control", input.asset.cacheControl);
1110
+ return new Response(body, { headers });
1050
1111
  }
1051
1112
  function applyHttpMetadata(headers, metadata) {
1052
- if (!metadata) return;
1053
- if (metadata.contentType && !headers.has("content-type")) headers.set("content-type", metadata.contentType);
1054
- if (metadata.cacheControl && !headers.has("cache-control")) headers.set("cache-control", metadata.cacheControl);
1055
- if (metadata.contentDisposition && !headers.has("content-disposition")) {
1056
- headers.set("content-disposition", metadata.contentDisposition);
1057
- }
1058
- if (metadata.contentEncoding && !headers.has("content-encoding")) headers.set("content-encoding", metadata.contentEncoding);
1059
- if (metadata.contentLanguage && !headers.has("content-language")) headers.set("content-language", metadata.contentLanguage);
1113
+ if (!metadata) return;
1114
+ if (metadata.contentType && !headers.has("content-type")) headers.set("content-type", metadata.contentType);
1115
+ if (metadata.cacheControl && !headers.has("cache-control")) headers.set("cache-control", metadata.cacheControl);
1116
+ if (metadata.contentDisposition && !headers.has("content-disposition")) headers.set("content-disposition", metadata.contentDisposition);
1117
+ if (metadata.contentEncoding && !headers.has("content-encoding")) headers.set("content-encoding", metadata.contentEncoding);
1118
+ if (metadata.contentLanguage && !headers.has("content-language")) headers.set("content-language", metadata.contentLanguage);
1060
1119
  }
1061
1120
  function resolveCacheControl(input, options) {
1062
- return typeof options.cacheControl === "function" ? options.cacheControl(input) : options.cacheControl;
1121
+ return typeof options.cacheControl === "function" ? options.cacheControl(input) : options.cacheControl;
1063
1122
  }
1064
- export {
1065
- SLIDE_TRANSITIONS,
1066
- createDeckPaths,
1067
- createDeckViewerEmbed,
1068
- defineDecksConfig,
1069
- defineSlideComponents,
1070
- withR2Assets
1071
- };
1123
+ //#endregion
1124
+ export { SLIDE_TRANSITIONS, createDeckPaths, createDeckViewerEmbed, defineDecksConfig, defineSlideComponents, withR2Assets };