tiny-essentials 1.29.0 → 1.29.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.
Files changed (131) hide show
  1. package/changelog/1/29/1.md +11 -0
  2. package/changelog/1/29/2.md +82 -0
  3. package/dist/v1/TinyBasicsEs.min.js +1 -1
  4. package/dist/v1/TinyEssentials.min.js +1 -1
  5. package/dist/v1/TinyFetchLoader.min.js +1 -0
  6. package/dist/v1/TinyImageLoader.min.js +1 -0
  7. package/dist/v1/TinyMediaCache.min.js +1 -0
  8. package/dist/v1/TinyMediaLoader.min.js +1 -0
  9. package/dist/v1/basics/index.cjs +5 -0
  10. package/dist/v1/basics/index.d.mts +2 -1
  11. package/dist/v1/basics/index.d.mts.map +1 -1
  12. package/dist/v1/basics/index.mjs +2 -1
  13. package/dist/v1/basics/media/youtube.cjs +275 -0
  14. package/dist/v1/basics/media/youtube.d.mts +107 -0
  15. package/dist/v1/basics/media/youtube.d.mts.map +1 -0
  16. package/dist/v1/basics/media/youtube.mjs +214 -0
  17. package/dist/v1/index.cjs +13 -0
  18. package/dist/v1/index.d.mts +6 -1
  19. package/dist/v1/index.d.mts.map +1 -1
  20. package/dist/v1/index.mjs +7 -2
  21. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.cjs +0 -1
  22. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.d.mts +0 -1
  23. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.d.mts.map +1 -1
  24. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.mjs +0 -1
  25. package/dist/v1/libs/fs/plugins/OPFS/index.cjs +0 -8
  26. package/dist/v1/libs/fs/plugins/OPFS/index.d.mts +0 -8
  27. package/dist/v1/libs/fs/plugins/OPFS/index.d.mts.map +1 -1
  28. package/dist/v1/libs/fs/plugins/OPFS/index.mjs +0 -8
  29. package/dist/v1/libs/html/TinyHtml.cjs +1 -1
  30. package/dist/v1/libs/html/TinyHtml.d.mts +2 -2
  31. package/dist/v1/libs/html/TinyHtml.d.mts.map +1 -1
  32. package/dist/v1/libs/html/TinyHtml.mjs +1 -1
  33. package/dist/v1/libs/html/loader/TinyMediaLoader.cjs +1999 -0
  34. package/dist/v1/libs/html/loader/TinyMediaLoader.d.mts +999 -0
  35. package/dist/v1/libs/html/loader/TinyMediaLoader.d.mts.map +1 -0
  36. package/dist/v1/libs/html/loader/TinyMediaLoader.mjs +1852 -0
  37. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.cjs +77 -0
  38. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.d.mts +103 -0
  39. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.d.mts.map +1 -0
  40. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.mjs +67 -0
  41. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.cjs +630 -0
  42. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.d.mts +138 -0
  43. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.d.mts.map +1 -0
  44. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.mjs +576 -0
  45. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.cjs +70 -0
  46. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.d.mts +100 -0
  47. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.d.mts.map +1 -0
  48. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.mjs +60 -0
  49. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.cjs +946 -0
  50. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.d.mts +67 -0
  51. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.d.mts.map +1 -0
  52. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.mjs +896 -0
  53. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.cjs +225 -0
  54. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.d.mts +149 -0
  55. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.d.mts.map +1 -0
  56. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.mjs +197 -0
  57. package/dist/v1/libs/html/loader/formats/TinyImageLoader.cjs +1454 -0
  58. package/dist/v1/libs/html/loader/formats/TinyImageLoader.d.mts +200 -0
  59. package/dist/v1/libs/html/loader/formats/TinyImageLoader.d.mts.map +1 -0
  60. package/dist/v1/libs/html/loader/formats/TinyImageLoader.mjs +1317 -0
  61. package/dist/v1/libs/html/loader/probe/TinyImageProbe.cjs +668 -0
  62. package/dist/v1/libs/html/loader/probe/TinyImageProbe.d.mts +83 -0
  63. package/dist/v1/libs/html/loader/probe/TinyImageProbe.d.mts.map +1 -0
  64. package/dist/v1/libs/html/loader/probe/TinyImageProbe.mjs +626 -0
  65. package/dist/v1/libs/html/loader/utils/TinyBufferReader.cjs +277 -0
  66. package/dist/v1/libs/html/loader/utils/TinyBufferReader.d.mts +118 -0
  67. package/dist/v1/libs/html/loader/utils/TinyBufferReader.d.mts.map +1 -0
  68. package/dist/v1/libs/html/loader/utils/TinyBufferReader.mjs +247 -0
  69. package/dist/v1/libs/html/loader/utils/TinyIsoBox.cjs +128 -0
  70. package/dist/v1/libs/html/loader/utils/TinyIsoBox.d.mts +49 -0
  71. package/dist/v1/libs/html/loader/utils/TinyIsoBox.d.mts.map +1 -0
  72. package/dist/v1/libs/html/loader/utils/TinyIsoBox.mjs +116 -0
  73. package/dist/v1/libs/html/loader/utils/TinyMediaCache.cjs +796 -0
  74. package/dist/v1/libs/html/loader/utils/TinyMediaCache.d.mts +354 -0
  75. package/dist/v1/libs/html/loader/utils/TinyMediaCache.d.mts.map +1 -0
  76. package/dist/v1/libs/html/loader/utils/TinyMediaCache.mjs +734 -0
  77. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.cjs +302 -0
  78. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.d.mts +256 -0
  79. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.d.mts.map +1 -0
  80. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.mjs +280 -0
  81. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.cjs +194 -0
  82. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.d.mts +138 -0
  83. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.d.mts.map +1 -0
  84. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.mjs +175 -0
  85. package/dist/v1/libs/tools/TinyPkgExportValidator.cjs +359 -55
  86. package/dist/v1/libs/tools/TinyPkgExportValidator.d.mts +64 -6
  87. package/dist/v1/libs/tools/TinyPkgExportValidator.d.mts.map +1 -1
  88. package/dist/v1/libs/tools/TinyPkgExportValidator.mjs +320 -57
  89. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.cjs +0 -1
  90. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.d.mts +0 -1
  91. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.d.mts.map +1 -1
  92. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.mjs +0 -1
  93. package/dist/v1/webTemplates/bootstrap/5.3/scss/background/_background-grid.scss +15 -0
  94. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/buttons/_buttons-contrast.scss +208 -0
  95. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/buttons/_buttons-ghost.scss +89 -0
  96. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/icon/_cube-icon.scss +65 -0
  97. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/icon/_sphere-pulse.scss +39 -0
  98. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_badges.scss +90 -0
  99. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_bootstrap-overrides.scss +495 -0
  100. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_buttons.scss +390 -0
  101. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_colors.scss +213 -0
  102. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_effects.scss +153 -0
  103. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_forms-tones.scss +69 -0
  104. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_forms.scss +323 -0
  105. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_global.scss +31 -0
  106. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_links.scss +47 -0
  107. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_tables.scss +25 -0
  108. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_theme.scss +21 -0
  109. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_tokens.scss +161 -0
  110. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_utilities.scss +81 -0
  111. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_variables.scss +63 -0
  112. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_form-tone-mixins.scss +236 -0
  113. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_sizing.scss +68 -0
  114. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_tone-mixins.scss +392 -0
  115. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_typography.scss +112 -0
  116. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/background/_tiny_gradient_1.scss +131 -0
  117. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/colors/_pink.scss +47 -0
  118. package/dist/v1/webTemplates/multiformats/14.0/IPFSHasher/index.cjs +2 -2
  119. package/docs/v1/Exports.md +33 -2
  120. package/docs/v1/README.md +9 -0
  121. package/docs/v1/basics/youtube.md +204 -0
  122. package/docs/v1/libs/html/loader/TinyFetchLoader.md +114 -0
  123. package/docs/v1/libs/html/loader/TinyImageLoader.md +141 -0
  124. package/docs/v1/libs/html/loader/TinyMediaCache.md +166 -0
  125. package/docs/v1/libs/html/loader/TinyMediaLoader.md +300 -0
  126. package/docs/v1/libs/tools/TinyPkgExportValidator.md +55 -0
  127. package/docs/v1/webTemplates/ag-psd/31.0/ProcessSolidFilters.md +0 -4
  128. package/docs/v1/webTemplates/bootstrap/5.3/DeepStrap.md +177 -0
  129. package/package.json +281 -17
  130. /package/dist/v1/webTemplates/bootstrap/5.3/scss/input/{Placeholder-Colors-Fix.scss → _placeholder-colors-fix.scss} +0 -0
  131. /package/dist/v1/webTemplates/bootstrap/5.3/scss/spacing/{Spacing-Plus.scss → _spacing-plus.scss} +0 -0
@@ -0,0 +1,275 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @typedef {'default' | 'mqdefault' | 'hqdefault' | 'sddefault' | 'maxresdefault'} YouTubeThumbnailQuality
5
+ */
6
+
7
+ /**
8
+ * @typedef {Object} YouTubeOEmbedResponse
9
+ * @property {string} title - Video title.
10
+ * @property {string} author_name - Channel display name.
11
+ * @property {string} author_url - Channel URL.
12
+ * @property {string} type - Resource type returned by the provider (e.g. "video").
13
+ * @property {string} version - oEmbed version.
14
+ * @property {string} provider_name - Always "YouTube".
15
+ * @property {string} provider_url - Provider root URL.
16
+ * @property {string} html - Ready to use iframe markup.
17
+ * @property {number} width - Suggested iframe width in pixels.
18
+ * @property {number} height - Suggested iframe height in pixels.
19
+ * @property {string} thumbnail_url - Thumbnail URL provided by the provider.
20
+ * @property {number} thumbnail_width - Thumbnail width in pixels.
21
+ * @property {number} thumbnail_height - Thumbnail height in pixels.
22
+ */
23
+
24
+ /**
25
+ * @typedef {Object} FetchYouTubeOEmbedOptions
26
+ * @property {AbortSignal} [signal] - Optional abort signal forwarded to fetch.
27
+ * @property {typeof fetch} [fetchImpl] - Injectable fetch implementation (useful for tests).
28
+ */
29
+
30
+ const YOUTUBE_VIDEO_ID_PATTERN = /^[A-Za-z0-9_-]{11}$/;
31
+ const YOUTUBE_OEMBED_ENDPOINT = 'https://www.youtube.com/oembed';
32
+ const YOUTUBE_THUMBNAIL_ENDPOINT = 'https://i.ytimg.com/vi';
33
+ const YOUTUBE_ALLOWED_HOSTS = new Set([
34
+ 'youtube.com',
35
+ 'm.youtube.com',
36
+ 'music.youtube.com',
37
+ 'youtube-nocookie.com',
38
+ 'youtu.be',
39
+ ]);
40
+ const YOUTUBE_ALLOWED_PROTOCOLS = new Set(['http:', 'https:']);
41
+ const YOUTUBE_THUMBNAIL_QUALITIES = new Set([
42
+ 'default',
43
+ 'mqdefault',
44
+ 'hqdefault',
45
+ 'sddefault',
46
+ 'maxresdefault',
47
+ ]);
48
+
49
+ const YOUTUBE_OEMBED_TYPE = 'video';
50
+
51
+ /**
52
+ * @param {unknown} value - Value to inspect.
53
+ * @param {string} label - Human readable path used in the error message.
54
+ * @returns {Record<string, unknown>} The same value, narrowed to a plain object.
55
+ * @throws {TypeError} If `value` is not a non-null, non-array object.
56
+ */
57
+ function assertPlainObject(value, label) {
58
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
59
+ throw new TypeError(
60
+ `${label} must be a plain object, received ${Array.isArray(value) ? 'array' : typeof value}.`,
61
+ );
62
+ }
63
+
64
+ return /** @type {Record<string, unknown>} */ (value);
65
+ }
66
+
67
+ /**
68
+ * @param {Record<string, unknown>} payload - Object being read.
69
+ * @param {string} key - Property name.
70
+ * @param {string} context - Caller name used in the error message.
71
+ * @returns {string} The validated, trimmed string.
72
+ * @throws {TypeError} If the property is not a string.
73
+ * @throws {RangeError} If the property is an empty string.
74
+ */
75
+ function readRequiredString(payload, key, context) {
76
+ const value = payload[key];
77
+
78
+ if (typeof value !== 'string') {
79
+ throw new TypeError(`${context}: "${key}" must be a string, received ${typeof value}.`);
80
+ }
81
+
82
+ const trimmed = value.trim();
83
+
84
+ if (trimmed.length === 0) {
85
+ throw new RangeError(`${context}: "${key}" cannot be empty.`);
86
+ }
87
+
88
+ return trimmed;
89
+ }
90
+
91
+ /**
92
+ * @param {Record<string, unknown>} payload - Object being read.
93
+ * @param {string} key - Property name.
94
+ * @param {string} context - Caller name used in the error message.
95
+ * @returns {number} The validated integer.
96
+ * @throws {TypeError} If the property is not a number.
97
+ * @throws {RangeError} If the property is not a positive integer.
98
+ */
99
+ function readRequiredPositiveInteger(payload, key, context) {
100
+ const value = payload[key];
101
+
102
+ if (typeof value !== 'number') {
103
+ throw new TypeError(`${context}: "${key}" must be a number, received ${typeof value}.`);
104
+ }
105
+
106
+ if (!Number.isInteger(value) || value <= 0) {
107
+ throw new RangeError(`${context}: "${key}" must be a positive integer, received ${value}.`);
108
+ }
109
+
110
+ return value;
111
+ }
112
+
113
+ /**
114
+ * Deeply validates a YouTube oEmbed payload.
115
+ * @param {unknown} payload - Raw value returned by `response.json()`.
116
+ * @param {string} [context='assertYouTubeOEmbedResponse'] - Caller name used in error messages.
117
+ * @returns {YouTubeOEmbedResponse} A brand new, fully validated object.
118
+ * @throws {TypeError} If the payload or any of its properties has the wrong type.
119
+ * @throws {RangeError} If a numeric property is not a positive integer.
120
+ */
121
+ function assertYouTubeOEmbedResponse(payload, context = 'assertYouTubeOEmbedResponse') {
122
+ const source = assertPlainObject(payload, `${context}: payload`);
123
+ const type = readRequiredString(source, 'type', context);
124
+
125
+ if (type !== YOUTUBE_OEMBED_TYPE) {
126
+ throw new RangeError(
127
+ `${context}: "type" must be "${YOUTUBE_OEMBED_TYPE}", received "${type}".`,
128
+ );
129
+ }
130
+
131
+ return {
132
+ title: readRequiredString(source, 'title', context),
133
+ author_name: readRequiredString(source, 'author_name', context),
134
+ author_url: readRequiredString(source, 'author_url', context),
135
+ type,
136
+ version: readRequiredString(source, 'version', context),
137
+ provider_name: readRequiredString(source, 'provider_name', context),
138
+ provider_url: readRequiredString(source, 'provider_url', context),
139
+ html: readRequiredString(source, 'html', context),
140
+ width: readRequiredPositiveInteger(source, 'width', context),
141
+ height: readRequiredPositiveInteger(source, 'height', context),
142
+ thumbnail_url: readRequiredString(source, 'thumbnail_url', context),
143
+ thumbnail_width: readRequiredPositiveInteger(source, 'thumbnail_width', context),
144
+ thumbnail_height: readRequiredPositiveInteger(source, 'thumbnail_height', context),
145
+ };
146
+ }
147
+
148
+ /**
149
+ * Extracts a YouTube video id from a raw id or a full YouTube URL.
150
+ * @param {string} input - Raw 11 character video id or a full YouTube URL.
151
+ * @returns {string} The 11 character video id.
152
+ * @throws {TypeError} If `input` is not a string.
153
+ * @throws {RangeError} If `input` is empty or the host is not a YouTube host.
154
+ * @throws {SyntaxError} If `input` is not a valid id nor a parseable URL containing an id.
155
+ */
156
+ function extractYouTubeVideoId(input) {
157
+ if (typeof input !== 'string') {
158
+ throw new TypeError('extractYouTubeVideoId: "input" must be a string.');
159
+ }
160
+
161
+ const trimmedInput = input.trim();
162
+
163
+ if (trimmedInput.length === 0) {
164
+ throw new RangeError('extractYouTubeVideoId: "input" cannot be empty.');
165
+ }
166
+
167
+ if (YOUTUBE_VIDEO_ID_PATTERN.test(trimmedInput)) {
168
+ return trimmedInput;
169
+ }
170
+
171
+ let parsedUrl;
172
+
173
+ try {
174
+ parsedUrl = new URL(trimmedInput);
175
+ } catch {
176
+ throw new SyntaxError(
177
+ `extractYouTubeVideoId: "${input}" is neither a video id nor a valid URL.`,
178
+ );
179
+ }
180
+
181
+ if (!YOUTUBE_ALLOWED_PROTOCOLS.has(parsedUrl.protocol)) {
182
+ throw new RangeError(`extractYouTubeVideoId: unsupported protocol "${parsedUrl.protocol}".`);
183
+ }
184
+
185
+ const host = parsedUrl.hostname.replace(/^www\./, '').toLowerCase();
186
+
187
+ if (!YOUTUBE_ALLOWED_HOSTS.has(host)) {
188
+ throw new RangeError(`extractYouTubeVideoId: unsupported host "${host}".`);
189
+ }
190
+
191
+ const pathMatch = parsedUrl.pathname.match(/^\/(?:embed|shorts|live|v)\/([A-Za-z0-9_-]{11})/);
192
+ const videoId =
193
+ host === 'youtu.be'
194
+ ? parsedUrl.pathname.slice(1).split('/')[0]
195
+ : (parsedUrl.searchParams.get('v') ?? pathMatch?.[1] ?? null);
196
+
197
+ if (typeof videoId !== 'string' || !YOUTUBE_VIDEO_ID_PATTERN.test(videoId)) {
198
+ throw new SyntaxError(`extractYouTubeVideoId: no valid video id found in "${input}".`);
199
+ }
200
+
201
+ return videoId;
202
+ }
203
+
204
+ /**
205
+ * Fetches the oEmbed metadata of a YouTube video.
206
+ * @param {string} videoIdOrUrl - Raw 11 character video id or a full YouTube URL.
207
+ * @param {FetchYouTubeOEmbedOptions} [options] - Optional fetch configuration.
208
+ * @returns {Promise<YouTubeOEmbedResponse>} The fully validated oEmbed payload.
209
+ * @throws {TypeError} If `options` is not a plain object, if `options.signal` is not an `AbortSignal`,
210
+ * if `options.fetchImpl` is not a function, or if the payload has a wrong type.
211
+ * @throws {RangeError} If the payload contains an out of range numeric value.
212
+ * @throws {Error} If the HTTP request fails or returns a non 2xx status.
213
+ */
214
+ async function fetchYouTubeOEmbed(videoIdOrUrl, options = {}) {
215
+ const context = 'fetchYouTubeOEmbed';
216
+ const settings = assertPlainObject(options, `${context}: "options"`);
217
+ const { signal, fetchImpl = fetch } = settings;
218
+
219
+ if (signal !== undefined && !(signal instanceof AbortSignal)) {
220
+ throw new TypeError(`${context}: "options.signal" must be an AbortSignal.`);
221
+ }
222
+
223
+ if (typeof fetchImpl !== 'function') {
224
+ throw new TypeError(`${context}: "options.fetchImpl" must be a function.`);
225
+ }
226
+
227
+ const videoId = extractYouTubeVideoId(videoIdOrUrl);
228
+ const endpoint = new URL(YOUTUBE_OEMBED_ENDPOINT);
229
+
230
+ endpoint.searchParams.set('format', 'json');
231
+ endpoint.searchParams.set('url', `https://www.youtube.com/watch?v=${videoId}`);
232
+
233
+ const response = await fetchImpl(endpoint, { method: 'GET', signal });
234
+
235
+ if (typeof response !== 'object' || response === null || typeof response.json !== 'function') {
236
+ throw new TypeError(`${context}: "options.fetchImpl" did not resolve to a Response.`);
237
+ }
238
+
239
+ if (!response.ok) {
240
+ throw new Error(
241
+ `${context}: request failed with status ${response.status} for video "${videoId}".`,
242
+ );
243
+ }
244
+
245
+ return assertYouTubeOEmbedResponse(await response.json(), context);
246
+ }
247
+
248
+ /**
249
+ * Builds the thumbnail URL of a YouTube video without any network request.
250
+ * @param {string} videoIdOrUrl - Raw 11 character video id or a full YouTube URL.
251
+ * @param {YouTubeThumbnailQuality} [quality='hqdefault'] - Thumbnail resolution.
252
+ * @returns {string} The thumbnail URL.
253
+ * @throws {TypeError} If `quality` is not a string.
254
+ * @throws {RangeError} If `quality` is not a supported thumbnail quality.
255
+ */
256
+ function getYouTubeThumbnailUrl(videoIdOrUrl, quality = 'hqdefault') {
257
+ if (typeof quality !== 'string') {
258
+ throw new TypeError(
259
+ `getYouTubeThumbnailUrl: "quality" must be a string, received ${typeof quality}.`,
260
+ );
261
+ }
262
+
263
+ if (!YOUTUBE_THUMBNAIL_QUALITIES.has(quality)) {
264
+ throw new RangeError(
265
+ `getYouTubeThumbnailUrl: "quality" must be one of ${[...YOUTUBE_THUMBNAIL_QUALITIES].join(', ')}.`,
266
+ );
267
+ }
268
+
269
+ return `${YOUTUBE_THUMBNAIL_ENDPOINT}/${extractYouTubeVideoId(videoIdOrUrl)}/${quality}.jpg`;
270
+ }
271
+
272
+ exports.assertYouTubeOEmbedResponse = assertYouTubeOEmbedResponse;
273
+ exports.extractYouTubeVideoId = extractYouTubeVideoId;
274
+ exports.fetchYouTubeOEmbed = fetchYouTubeOEmbed;
275
+ exports.getYouTubeThumbnailUrl = getYouTubeThumbnailUrl;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @typedef {'default' | 'mqdefault' | 'hqdefault' | 'sddefault' | 'maxresdefault'} YouTubeThumbnailQuality
3
+ */
4
+ export type YouTubeThumbnailQuality = 'default' | 'mqdefault' | 'hqdefault' | 'sddefault' | 'maxresdefault';
5
+ export type YouTubeOEmbedResponse = {
6
+ /**
7
+ * - Video title.
8
+ */
9
+ title: string;
10
+ /**
11
+ * - Channel display name.
12
+ */
13
+ author_name: string;
14
+ /**
15
+ * - Channel URL.
16
+ */
17
+ author_url: string;
18
+ /**
19
+ * - Resource type returned by the provider (e.g. "video").
20
+ */
21
+ type: string;
22
+ /**
23
+ * - oEmbed version.
24
+ */
25
+ version: string;
26
+ /**
27
+ * - Always "YouTube".
28
+ */
29
+ provider_name: string;
30
+ /**
31
+ * - Provider root URL.
32
+ */
33
+ provider_url: string;
34
+ /**
35
+ * - Ready to use iframe markup.
36
+ */
37
+ html: string;
38
+ /**
39
+ * - Suggested iframe width in pixels.
40
+ */
41
+ width: number;
42
+ /**
43
+ * - Suggested iframe height in pixels.
44
+ */
45
+ height: number;
46
+ /**
47
+ * - Thumbnail URL provided by the provider.
48
+ */
49
+ thumbnail_url: string;
50
+ /**
51
+ * - Thumbnail width in pixels.
52
+ */
53
+ thumbnail_width: number;
54
+ /**
55
+ * - Thumbnail height in pixels.
56
+ */
57
+ thumbnail_height: number;
58
+ };
59
+ export type FetchYouTubeOEmbedOptions = {
60
+ /**
61
+ * - Optional abort signal forwarded to fetch.
62
+ */
63
+ signal?: AbortSignal;
64
+ /**
65
+ * - Injectable fetch implementation (useful for tests).
66
+ */
67
+ fetchImpl?: typeof fetch;
68
+ };
69
+ /**
70
+ * Deeply validates a YouTube oEmbed payload.
71
+ * @param {unknown} payload - Raw value returned by `response.json()`.
72
+ * @param {string} [context='assertYouTubeOEmbedResponse'] - Caller name used in error messages.
73
+ * @returns {YouTubeOEmbedResponse} A brand new, fully validated object.
74
+ * @throws {TypeError} If the payload or any of its properties has the wrong type.
75
+ * @throws {RangeError} If a numeric property is not a positive integer.
76
+ */
77
+ export declare function assertYouTubeOEmbedResponse(payload: unknown, context?: string): YouTubeOEmbedResponse;
78
+ /**
79
+ * Extracts a YouTube video id from a raw id or a full YouTube URL.
80
+ * @param {string} input - Raw 11 character video id or a full YouTube URL.
81
+ * @returns {string} The 11 character video id.
82
+ * @throws {TypeError} If `input` is not a string.
83
+ * @throws {RangeError} If `input` is empty or the host is not a YouTube host.
84
+ * @throws {SyntaxError} If `input` is not a valid id nor a parseable URL containing an id.
85
+ */
86
+ export declare function extractYouTubeVideoId(input: string): string;
87
+ /**
88
+ * Fetches the oEmbed metadata of a YouTube video.
89
+ * @param {string} videoIdOrUrl - Raw 11 character video id or a full YouTube URL.
90
+ * @param {FetchYouTubeOEmbedOptions} [options] - Optional fetch configuration.
91
+ * @returns {Promise<YouTubeOEmbedResponse>} The fully validated oEmbed payload.
92
+ * @throws {TypeError} If `options` is not a plain object, if `options.signal` is not an `AbortSignal`,
93
+ * if `options.fetchImpl` is not a function, or if the payload has a wrong type.
94
+ * @throws {RangeError} If the payload contains an out of range numeric value.
95
+ * @throws {Error} If the HTTP request fails or returns a non 2xx status.
96
+ */
97
+ export declare function fetchYouTubeOEmbed(videoIdOrUrl: string, options?: FetchYouTubeOEmbedOptions): Promise<YouTubeOEmbedResponse>;
98
+ /**
99
+ * Builds the thumbnail URL of a YouTube video without any network request.
100
+ * @param {string} videoIdOrUrl - Raw 11 character video id or a full YouTube URL.
101
+ * @param {YouTubeThumbnailQuality} [quality='hqdefault'] - Thumbnail resolution.
102
+ * @returns {string} The thumbnail URL.
103
+ * @throws {TypeError} If `quality` is not a string.
104
+ * @throws {RangeError} If `quality` is not a supported thumbnail quality.
105
+ */
106
+ export declare function getYouTubeThumbnailUrl(videoIdOrUrl: string, quality?: YouTubeThumbnailQuality): string;
107
+ //# sourceMappingURL=youtube.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"youtube.d.mts","sourceRoot":"","sources":["../../../../src/v1/basics/media/youtube.mjs"],"names":[],"mappings":"AAAA;;GAEG;AADA,YAAiF,uBAAuB,GAA9F,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,eAAe,CAAyB;AAIxG,YAAkB,qBAAqB,GACvC;;;;IAAmB,KAAK,EAAb,MAAM,CACjB;;;;IAAmB,WAAW,EAAnB,MAAM,CACjB;;;;IAAmB,UAAU,EAAlB,MAAM,CACjB;;;;IAAmB,IAAI,EAAZ,MAAM,CACjB;;;;IAAmB,OAAO,EAAf,MAAM,CACjB;;;;IAAmB,aAAa,EAArB,MAAM,CACjB;;;;IAAmB,YAAY,EAApB,MAAM,CACjB;;;;IAAmB,IAAI,EAAZ,MAAM,CACjB;;;;IAAmB,KAAK,EAAb,MAAM,CACjB;;;;IAAmB,MAAM,EAAd,MAAM,CACjB;;;;IAAmB,aAAa,EAArB,MAAM,CACjB;;;;IAAmB,eAAe,EAAvB,MAAM,CACjB;;;;IAAmB,gBAAgB,EAAxB,MAAM,CACnB;CAAA,CAAA;AAGE,YAAkB,yBAAyB,GAC3C;;;;IAAyB,MAAM,AAA/B,CACA,EADW,WAAW,CACtB;;;;IAA0B,SAAS,AAAnC,CACF,EADa,OAAO,KAAK,CACzB;CAAA,CAAA;AAqFD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EANxC,OAMwC,EAAE,OAAO,AALzD,CACA,EADQ,MAKiF,GAJ/E,qBAAqB,CA6BjC;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EANhC,MAMgC,GAL9B,MAAM,CAmDlB;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CAAC,YAAY,EAR1C,MAQ0C,EAAE,OAAO,AAP3D,CACA,EADQ,yBAOwD,GANtD,OAAO,CAAC,qBAAqB,CAAC,CAsC1C;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EANxC,MAMwC,EAAE,OAAO,AALzD,CACA,EADQ,uBAK+D,GAJ7D,MAAM,CAkBlB"}
@@ -0,0 +1,214 @@
1
+ /**
2
+ * @typedef {'default' | 'mqdefault' | 'hqdefault' | 'sddefault' | 'maxresdefault'} YouTubeThumbnailQuality
3
+ */
4
+ /**
5
+ * @typedef {Object} YouTubeOEmbedResponse
6
+ * @property {string} title - Video title.
7
+ * @property {string} author_name - Channel display name.
8
+ * @property {string} author_url - Channel URL.
9
+ * @property {string} type - Resource type returned by the provider (e.g. "video").
10
+ * @property {string} version - oEmbed version.
11
+ * @property {string} provider_name - Always "YouTube".
12
+ * @property {string} provider_url - Provider root URL.
13
+ * @property {string} html - Ready to use iframe markup.
14
+ * @property {number} width - Suggested iframe width in pixels.
15
+ * @property {number} height - Suggested iframe height in pixels.
16
+ * @property {string} thumbnail_url - Thumbnail URL provided by the provider.
17
+ * @property {number} thumbnail_width - Thumbnail width in pixels.
18
+ * @property {number} thumbnail_height - Thumbnail height in pixels.
19
+ */
20
+ /**
21
+ * @typedef {Object} FetchYouTubeOEmbedOptions
22
+ * @property {AbortSignal} [signal] - Optional abort signal forwarded to fetch.
23
+ * @property {typeof fetch} [fetchImpl] - Injectable fetch implementation (useful for tests).
24
+ */
25
+ const YOUTUBE_VIDEO_ID_PATTERN = /^[A-Za-z0-9_-]{11}$/;
26
+ const YOUTUBE_OEMBED_ENDPOINT = 'https://www.youtube.com/oembed';
27
+ const YOUTUBE_THUMBNAIL_ENDPOINT = 'https://i.ytimg.com/vi';
28
+ const YOUTUBE_ALLOWED_HOSTS = new Set([
29
+ 'youtube.com',
30
+ 'm.youtube.com',
31
+ 'music.youtube.com',
32
+ 'youtube-nocookie.com',
33
+ 'youtu.be',
34
+ ]);
35
+ const YOUTUBE_ALLOWED_PROTOCOLS = new Set(['http:', 'https:']);
36
+ const YOUTUBE_THUMBNAIL_QUALITIES = new Set([
37
+ 'default',
38
+ 'mqdefault',
39
+ 'hqdefault',
40
+ 'sddefault',
41
+ 'maxresdefault',
42
+ ]);
43
+ const YOUTUBE_OEMBED_TYPE = 'video';
44
+ /**
45
+ * @param {unknown} value - Value to inspect.
46
+ * @param {string} label - Human readable path used in the error message.
47
+ * @returns {Record<string, unknown>} The same value, narrowed to a plain object.
48
+ * @throws {TypeError} If `value` is not a non-null, non-array object.
49
+ */
50
+ function assertPlainObject(value, label) {
51
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
52
+ throw new TypeError(`${label} must be a plain object, received ${Array.isArray(value) ? 'array' : typeof value}.`);
53
+ }
54
+ return /** @type {Record<string, unknown>} */ (value);
55
+ }
56
+ /**
57
+ * @param {Record<string, unknown>} payload - Object being read.
58
+ * @param {string} key - Property name.
59
+ * @param {string} context - Caller name used in the error message.
60
+ * @returns {string} The validated, trimmed string.
61
+ * @throws {TypeError} If the property is not a string.
62
+ * @throws {RangeError} If the property is an empty string.
63
+ */
64
+ function readRequiredString(payload, key, context) {
65
+ const value = payload[key];
66
+ if (typeof value !== 'string') {
67
+ throw new TypeError(`${context}: "${key}" must be a string, received ${typeof value}.`);
68
+ }
69
+ const trimmed = value.trim();
70
+ if (trimmed.length === 0) {
71
+ throw new RangeError(`${context}: "${key}" cannot be empty.`);
72
+ }
73
+ return trimmed;
74
+ }
75
+ /**
76
+ * @param {Record<string, unknown>} payload - Object being read.
77
+ * @param {string} key - Property name.
78
+ * @param {string} context - Caller name used in the error message.
79
+ * @returns {number} The validated integer.
80
+ * @throws {TypeError} If the property is not a number.
81
+ * @throws {RangeError} If the property is not a positive integer.
82
+ */
83
+ function readRequiredPositiveInteger(payload, key, context) {
84
+ const value = payload[key];
85
+ if (typeof value !== 'number') {
86
+ throw new TypeError(`${context}: "${key}" must be a number, received ${typeof value}.`);
87
+ }
88
+ if (!Number.isInteger(value) || value <= 0) {
89
+ throw new RangeError(`${context}: "${key}" must be a positive integer, received ${value}.`);
90
+ }
91
+ return value;
92
+ }
93
+ /**
94
+ * Deeply validates a YouTube oEmbed payload.
95
+ * @param {unknown} payload - Raw value returned by `response.json()`.
96
+ * @param {string} [context='assertYouTubeOEmbedResponse'] - Caller name used in error messages.
97
+ * @returns {YouTubeOEmbedResponse} A brand new, fully validated object.
98
+ * @throws {TypeError} If the payload or any of its properties has the wrong type.
99
+ * @throws {RangeError} If a numeric property is not a positive integer.
100
+ */
101
+ export function assertYouTubeOEmbedResponse(payload, context = 'assertYouTubeOEmbedResponse') {
102
+ const source = assertPlainObject(payload, `${context}: payload`);
103
+ const type = readRequiredString(source, 'type', context);
104
+ if (type !== YOUTUBE_OEMBED_TYPE) {
105
+ throw new RangeError(`${context}: "type" must be "${YOUTUBE_OEMBED_TYPE}", received "${type}".`);
106
+ }
107
+ return {
108
+ title: readRequiredString(source, 'title', context),
109
+ author_name: readRequiredString(source, 'author_name', context),
110
+ author_url: readRequiredString(source, 'author_url', context),
111
+ type,
112
+ version: readRequiredString(source, 'version', context),
113
+ provider_name: readRequiredString(source, 'provider_name', context),
114
+ provider_url: readRequiredString(source, 'provider_url', context),
115
+ html: readRequiredString(source, 'html', context),
116
+ width: readRequiredPositiveInteger(source, 'width', context),
117
+ height: readRequiredPositiveInteger(source, 'height', context),
118
+ thumbnail_url: readRequiredString(source, 'thumbnail_url', context),
119
+ thumbnail_width: readRequiredPositiveInteger(source, 'thumbnail_width', context),
120
+ thumbnail_height: readRequiredPositiveInteger(source, 'thumbnail_height', context),
121
+ };
122
+ }
123
+ /**
124
+ * Extracts a YouTube video id from a raw id or a full YouTube URL.
125
+ * @param {string} input - Raw 11 character video id or a full YouTube URL.
126
+ * @returns {string} The 11 character video id.
127
+ * @throws {TypeError} If `input` is not a string.
128
+ * @throws {RangeError} If `input` is empty or the host is not a YouTube host.
129
+ * @throws {SyntaxError} If `input` is not a valid id nor a parseable URL containing an id.
130
+ */
131
+ export function extractYouTubeVideoId(input) {
132
+ if (typeof input !== 'string') {
133
+ throw new TypeError('extractYouTubeVideoId: "input" must be a string.');
134
+ }
135
+ const trimmedInput = input.trim();
136
+ if (trimmedInput.length === 0) {
137
+ throw new RangeError('extractYouTubeVideoId: "input" cannot be empty.');
138
+ }
139
+ if (YOUTUBE_VIDEO_ID_PATTERN.test(trimmedInput)) {
140
+ return trimmedInput;
141
+ }
142
+ let parsedUrl;
143
+ try {
144
+ parsedUrl = new URL(trimmedInput);
145
+ }
146
+ catch {
147
+ throw new SyntaxError(`extractYouTubeVideoId: "${input}" is neither a video id nor a valid URL.`);
148
+ }
149
+ if (!YOUTUBE_ALLOWED_PROTOCOLS.has(parsedUrl.protocol)) {
150
+ throw new RangeError(`extractYouTubeVideoId: unsupported protocol "${parsedUrl.protocol}".`);
151
+ }
152
+ const host = parsedUrl.hostname.replace(/^www\./, '').toLowerCase();
153
+ if (!YOUTUBE_ALLOWED_HOSTS.has(host)) {
154
+ throw new RangeError(`extractYouTubeVideoId: unsupported host "${host}".`);
155
+ }
156
+ const pathMatch = parsedUrl.pathname.match(/^\/(?:embed|shorts|live|v)\/([A-Za-z0-9_-]{11})/);
157
+ const videoId = host === 'youtu.be'
158
+ ? parsedUrl.pathname.slice(1).split('/')[0]
159
+ : (parsedUrl.searchParams.get('v') ?? pathMatch?.[1] ?? null);
160
+ if (typeof videoId !== 'string' || !YOUTUBE_VIDEO_ID_PATTERN.test(videoId)) {
161
+ throw new SyntaxError(`extractYouTubeVideoId: no valid video id found in "${input}".`);
162
+ }
163
+ return videoId;
164
+ }
165
+ /**
166
+ * Fetches the oEmbed metadata of a YouTube video.
167
+ * @param {string} videoIdOrUrl - Raw 11 character video id or a full YouTube URL.
168
+ * @param {FetchYouTubeOEmbedOptions} [options] - Optional fetch configuration.
169
+ * @returns {Promise<YouTubeOEmbedResponse>} The fully validated oEmbed payload.
170
+ * @throws {TypeError} If `options` is not a plain object, if `options.signal` is not an `AbortSignal`,
171
+ * if `options.fetchImpl` is not a function, or if the payload has a wrong type.
172
+ * @throws {RangeError} If the payload contains an out of range numeric value.
173
+ * @throws {Error} If the HTTP request fails or returns a non 2xx status.
174
+ */
175
+ export async function fetchYouTubeOEmbed(videoIdOrUrl, options = {}) {
176
+ const context = 'fetchYouTubeOEmbed';
177
+ const settings = assertPlainObject(options, `${context}: "options"`);
178
+ const { signal, fetchImpl = fetch } = settings;
179
+ if (signal !== undefined && !(signal instanceof AbortSignal)) {
180
+ throw new TypeError(`${context}: "options.signal" must be an AbortSignal.`);
181
+ }
182
+ if (typeof fetchImpl !== 'function') {
183
+ throw new TypeError(`${context}: "options.fetchImpl" must be a function.`);
184
+ }
185
+ const videoId = extractYouTubeVideoId(videoIdOrUrl);
186
+ const endpoint = new URL(YOUTUBE_OEMBED_ENDPOINT);
187
+ endpoint.searchParams.set('format', 'json');
188
+ endpoint.searchParams.set('url', `https://www.youtube.com/watch?v=${videoId}`);
189
+ const response = await fetchImpl(endpoint, { method: 'GET', signal });
190
+ if (typeof response !== 'object' || response === null || typeof response.json !== 'function') {
191
+ throw new TypeError(`${context}: "options.fetchImpl" did not resolve to a Response.`);
192
+ }
193
+ if (!response.ok) {
194
+ throw new Error(`${context}: request failed with status ${response.status} for video "${videoId}".`);
195
+ }
196
+ return assertYouTubeOEmbedResponse(await response.json(), context);
197
+ }
198
+ /**
199
+ * Builds the thumbnail URL of a YouTube video without any network request.
200
+ * @param {string} videoIdOrUrl - Raw 11 character video id or a full YouTube URL.
201
+ * @param {YouTubeThumbnailQuality} [quality='hqdefault'] - Thumbnail resolution.
202
+ * @returns {string} The thumbnail URL.
203
+ * @throws {TypeError} If `quality` is not a string.
204
+ * @throws {RangeError} If `quality` is not a supported thumbnail quality.
205
+ */
206
+ export function getYouTubeThumbnailUrl(videoIdOrUrl, quality = 'hqdefault') {
207
+ if (typeof quality !== 'string') {
208
+ throw new TypeError(`getYouTubeThumbnailUrl: "quality" must be a string, received ${typeof quality}.`);
209
+ }
210
+ if (!YOUTUBE_THUMBNAIL_QUALITIES.has(quality)) {
211
+ throw new RangeError(`getYouTubeThumbnailUrl: "quality" must be one of ${[...YOUTUBE_THUMBNAIL_QUALITIES].join(', ')}.`);
212
+ }
213
+ return `${YOUTUBE_THUMBNAIL_ENDPOINT}/${extractYouTubeVideoId(videoIdOrUrl)}/${quality}.jpg`;
214
+ }
package/dist/v1/index.cjs CHANGED
@@ -86,6 +86,11 @@ var StorageBucket = require('./libs/fs/plugins/OPFS/StorageBucket.cjs');
86
86
  var TinySetMapDatabase = require('./libs/storage/TinySetMapDatabase.cjs');
87
87
  var TinyPushManager = require('./libs/sw/browser/TinyPushManager.cjs');
88
88
  var TinyNotificationAdapter = require('./libs/sw/browser/TinyNotificationAdapter.cjs');
89
+ var TinyMediaLoader = require('./libs/html/loader/TinyMediaLoader.cjs');
90
+ var TinyImageLoader = require('./libs/html/loader/formats/TinyImageLoader.cjs');
91
+ var TinyFetchLoader = require('./libs/html/loader/formats/TinyFetchLoader.cjs');
92
+ var TinyMediaCache = require('./libs/html/loader/utils/TinyMediaCache.cjs');
93
+ var youtube = require('./basics/media/youtube.cjs');
89
94
 
90
95
 
91
96
 
@@ -307,3 +312,11 @@ exports.TinySetMapDatabase = TinySetMapDatabase.TinySetMapDatabase;
307
312
  exports.TinyTableDb = TinySetMapDatabase.TinyTableDb;
308
313
  exports.TinyPushManager = TinyPushManager;
309
314
  exports.TinyNotificationAdapter = TinyNotificationAdapter;
315
+ exports.TinyMediaLoader = TinyMediaLoader;
316
+ exports.TinyImageLoader = TinyImageLoader;
317
+ exports.TinyFetchLoader = TinyFetchLoader;
318
+ exports.TinyMediaCache = TinyMediaCache;
319
+ exports.assertYouTubeOEmbedResponse = youtube.assertYouTubeOEmbedResponse;
320
+ exports.extractYouTubeVideoId = youtube.extractYouTubeVideoId;
321
+ exports.fetchYouTubeOEmbed = youtube.fetchYouTubeOEmbed;
322
+ exports.getYouTubeThumbnailUrl = youtube.getYouTubeThumbnailUrl;
@@ -84,5 +84,10 @@ import TinyStorageBucketFileSystem from './libs/fs/plugins/OPFS/StorageBucket.mj
84
84
  import { TinySetMapDatabase, TinySetDb, TinyMapDb, TinyTableDb } from './libs/storage/TinySetMapDatabase.mjs';
85
85
  import TinyPushManager from './libs/sw/browser/TinyPushManager.mjs';
86
86
  import { TinyNotificationAdapter } from './build/TinyNotificationAdapter.mjs';
87
- export { TinyNotificationAdapter, TinyPushManager, TinySetMapDatabase, TinySetDb, TinyMapDb, TinyTableDb, TinyStorageBucketFileSystem, TinyOPFSFileSystem, TinyPluginLayer, TinyPlugin, TinyPluginCore, TinyVersion, TinyThrottledApi, TinyBrowserMonitor, TinyUriParser, TinyHtmlTagRegexBuilder, TinyHttpResponseRegistry, TinyCloner, TinyWebWorker, TinyServiceWorker, TinyMapCache, TinyRouter, TinyDebugger, TinyMediaPlayer, TinyRadioFm, TinyClassManager, FuzzySet, MamdaniInferenceSystem, TinyArrayComparator, TinyTextDiffer, TinyAnalogClock, TinyPkgExportValidator, TinyUploadClicker, TinyColorValidator, TinyLoadingScreen, TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, createPluginIdChecker, verifyPluginSignature, signPluginIdentity, isClass, isAnyClassInstance, isClassInstance, isValidGlob, compileGlob, compileGlobRegExp, decompileGlob, isBrowser, emailStringRegexBuilder, emailRegex, isValidEmail, findEmailRegex, extractEmails, usernameStringRegexBuilder, usernameRegex, isValidUsername, findUsernameRegex, extractUsernames, urlStringRegexBuilder, urlRegex, isValidUrl, findUrlRegex, extractUrls, ipv6Regex, isValidIPv6, findIPv6Regex, extractIPsV6, ipv4Regex, isValidIPv4, findIPv4Regex, extractIPsV4, getObjTypeRegistry, getObjTypeOrder, segmentExtractorV1, makeSegmentExtractor, jsonFilter, jsonFilterRecursive, jsonFilterByKeys, getUserTimeFormat, getBrowserPings, isBrowserAgent, getBrowserCssPrefix, getDuckTyping, browserIs, isValidObj, createSingletonTask, waitForTrue, multiplyArrayBlocks, createCheckDestroyed, valMediaContentMetadata, valFetchMediaContent, parseMediaMetadata, extractMediaId3Tags, defuzzifyCentroid, trapezoid, diffArrayList, hashText, diffObjList, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objTypeName, isObjType, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
87
+ import TinyMediaLoader from './libs/html/loader/TinyMediaLoader.mjs';
88
+ import TinyImageLoader from './libs/html/loader/formats/TinyImageLoader.mjs';
89
+ import TinyFetchLoader from './libs/html/loader/formats/TinyFetchLoader.mjs';
90
+ import TinyMediaCache from './libs/html/loader/utils/TinyMediaCache.mjs';
91
+ import { getYouTubeThumbnailUrl, fetchYouTubeOEmbed, extractYouTubeVideoId, assertYouTubeOEmbedResponse } from './basics/media/youtube.mjs';
92
+ export { TinyMediaCache, TinyMediaLoader, TinyImageLoader, TinyFetchLoader, TinyNotificationAdapter, TinyPushManager, TinySetMapDatabase, TinySetDb, TinyMapDb, TinyTableDb, TinyStorageBucketFileSystem, TinyOPFSFileSystem, TinyPluginLayer, TinyPlugin, TinyPluginCore, TinyVersion, TinyThrottledApi, TinyBrowserMonitor, TinyUriParser, TinyHtmlTagRegexBuilder, TinyHttpResponseRegistry, TinyCloner, TinyWebWorker, TinyServiceWorker, TinyMapCache, TinyRouter, TinyDebugger, TinyMediaPlayer, TinyRadioFm, TinyClassManager, FuzzySet, MamdaniInferenceSystem, TinyArrayComparator, TinyTextDiffer, TinyAnalogClock, TinyPkgExportValidator, TinyUploadClicker, TinyColorValidator, TinyLoadingScreen, TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, getYouTubeThumbnailUrl, fetchYouTubeOEmbed, extractYouTubeVideoId, assertYouTubeOEmbedResponse, createPluginIdChecker, verifyPluginSignature, signPluginIdentity, isClass, isAnyClassInstance, isClassInstance, isValidGlob, compileGlob, compileGlobRegExp, decompileGlob, isBrowser, emailStringRegexBuilder, emailRegex, isValidEmail, findEmailRegex, extractEmails, usernameStringRegexBuilder, usernameRegex, isValidUsername, findUsernameRegex, extractUsernames, urlStringRegexBuilder, urlRegex, isValidUrl, findUrlRegex, extractUrls, ipv6Regex, isValidIPv6, findIPv6Regex, extractIPsV6, ipv4Regex, isValidIPv4, findIPv4Regex, extractIPsV4, getObjTypeRegistry, getObjTypeOrder, segmentExtractorV1, makeSegmentExtractor, jsonFilter, jsonFilterRecursive, jsonFilterByKeys, getUserTimeFormat, getBrowserPings, isBrowserAgent, getBrowserCssPrefix, getDuckTyping, browserIs, isValidObj, createSingletonTask, waitForTrue, multiplyArrayBlocks, createCheckDestroyed, valMediaContentMetadata, valFetchMediaContent, parseMediaMetadata, extractMediaId3Tags, defuzzifyCentroid, trapezoid, diffArrayList, hashText, diffObjList, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objTypeName, isObjType, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
88
93
  //# sourceMappingURL=index.d.mts.map