@teleporthq/teleport-shared 0.43.67 → 0.43.69

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 (107) hide show
  1. package/__tests__/_helpers/embed-runtime-emitter.ts +197 -0
  2. package/__tests__/utils/discount-engine.ts +1548 -0
  3. package/__tests__/utils/product-options.ts +2458 -0
  4. package/__tests__/utils/rich-text-embeds-runtime-module.ts +34 -0
  5. package/__tests__/utils/subscription-access.ts +37 -0
  6. package/dist/cjs/index.d.ts +9 -1
  7. package/dist/cjs/index.d.ts.map +1 -1
  8. package/dist/cjs/index.js +17 -1
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  11. package/dist/cjs/utils/cart-currency.d.ts +27 -0
  12. package/dist/cjs/utils/cart-currency.d.ts.map +1 -0
  13. package/dist/cjs/utils/cart-currency.js +31 -0
  14. package/dist/cjs/utils/cart-currency.js.map +1 -0
  15. package/dist/cjs/utils/cart-line-pricing.d.ts +25 -0
  16. package/dist/cjs/utils/cart-line-pricing.d.ts.map +1 -0
  17. package/dist/cjs/utils/cart-line-pricing.js +29 -0
  18. package/dist/cjs/utils/cart-line-pricing.js.map +1 -0
  19. package/dist/cjs/utils/discount-engine.d.ts +74 -0
  20. package/dist/cjs/utils/discount-engine.d.ts.map +1 -0
  21. package/dist/cjs/utils/discount-engine.js +435 -0
  22. package/dist/cjs/utils/discount-engine.js.map +1 -0
  23. package/dist/cjs/utils/product-options.d.ts +25 -0
  24. package/dist/cjs/utils/product-options.d.ts.map +1 -0
  25. package/dist/cjs/utils/product-options.js +1155 -0
  26. package/dist/cjs/utils/product-options.js.map +1 -0
  27. package/dist/cjs/utils/rich-text-embeds-codegen.d.ts +13 -0
  28. package/dist/cjs/utils/rich-text-embeds-codegen.d.ts.map +1 -1
  29. package/dist/cjs/utils/rich-text-embeds-codegen.js +15 -104
  30. package/dist/cjs/utils/rich-text-embeds-codegen.js.map +1 -1
  31. package/dist/cjs/utils/rich-text-embeds-runtime-source.d.ts +2 -0
  32. package/dist/cjs/utils/rich-text-embeds-runtime-source.d.ts.map +1 -0
  33. package/dist/cjs/utils/rich-text-embeds-runtime-source.js +409 -0
  34. package/dist/cjs/utils/rich-text-embeds-runtime-source.js.map +1 -0
  35. package/dist/cjs/utils/session-cookie-resolver.d.ts +85 -0
  36. package/dist/cjs/utils/session-cookie-resolver.d.ts.map +1 -0
  37. package/dist/cjs/utils/session-cookie-resolver.js +108 -0
  38. package/dist/cjs/utils/session-cookie-resolver.js.map +1 -0
  39. package/dist/cjs/utils/subscription-access.d.ts +36 -0
  40. package/dist/cjs/utils/subscription-access.d.ts.map +1 -0
  41. package/dist/cjs/utils/subscription-access.js +61 -0
  42. package/dist/cjs/utils/subscription-access.js.map +1 -0
  43. package/dist/cjs/utils/table-access.d.ts +114 -0
  44. package/dist/cjs/utils/table-access.d.ts.map +1 -0
  45. package/dist/cjs/utils/table-access.js +238 -0
  46. package/dist/cjs/utils/table-access.js.map +1 -0
  47. package/dist/cjs/utils/web-push.d.ts +43 -0
  48. package/dist/cjs/utils/web-push.d.ts.map +1 -0
  49. package/dist/cjs/utils/web-push.js +62 -0
  50. package/dist/cjs/utils/web-push.js.map +1 -0
  51. package/dist/esm/index.d.ts +9 -1
  52. package/dist/esm/index.d.ts.map +1 -1
  53. package/dist/esm/index.js +9 -1
  54. package/dist/esm/index.js.map +1 -1
  55. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  56. package/dist/esm/utils/cart-currency.d.ts +27 -0
  57. package/dist/esm/utils/cart-currency.d.ts.map +1 -0
  58. package/dist/esm/utils/cart-currency.js +27 -0
  59. package/dist/esm/utils/cart-currency.js.map +1 -0
  60. package/dist/esm/utils/cart-line-pricing.d.ts +25 -0
  61. package/dist/esm/utils/cart-line-pricing.d.ts.map +1 -0
  62. package/dist/esm/utils/cart-line-pricing.js +25 -0
  63. package/dist/esm/utils/cart-line-pricing.js.map +1 -0
  64. package/dist/esm/utils/discount-engine.d.ts +74 -0
  65. package/dist/esm/utils/discount-engine.d.ts.map +1 -0
  66. package/dist/esm/utils/discount-engine.js +431 -0
  67. package/dist/esm/utils/discount-engine.js.map +1 -0
  68. package/dist/esm/utils/product-options.d.ts +25 -0
  69. package/dist/esm/utils/product-options.d.ts.map +1 -0
  70. package/dist/esm/utils/product-options.js +1151 -0
  71. package/dist/esm/utils/product-options.js.map +1 -0
  72. package/dist/esm/utils/rich-text-embeds-codegen.d.ts +13 -0
  73. package/dist/esm/utils/rich-text-embeds-codegen.d.ts.map +1 -1
  74. package/dist/esm/utils/rich-text-embeds-codegen.js +16 -105
  75. package/dist/esm/utils/rich-text-embeds-codegen.js.map +1 -1
  76. package/dist/esm/utils/rich-text-embeds-runtime-source.d.ts +2 -0
  77. package/dist/esm/utils/rich-text-embeds-runtime-source.d.ts.map +1 -0
  78. package/dist/esm/utils/rich-text-embeds-runtime-source.js +406 -0
  79. package/dist/esm/utils/rich-text-embeds-runtime-source.js.map +1 -0
  80. package/dist/esm/utils/session-cookie-resolver.d.ts +85 -0
  81. package/dist/esm/utils/session-cookie-resolver.d.ts.map +1 -0
  82. package/dist/esm/utils/session-cookie-resolver.js +103 -0
  83. package/dist/esm/utils/session-cookie-resolver.js.map +1 -0
  84. package/dist/esm/utils/subscription-access.d.ts +36 -0
  85. package/dist/esm/utils/subscription-access.d.ts.map +1 -0
  86. package/dist/esm/utils/subscription-access.js +57 -0
  87. package/dist/esm/utils/subscription-access.js.map +1 -0
  88. package/dist/esm/utils/table-access.d.ts +114 -0
  89. package/dist/esm/utils/table-access.d.ts.map +1 -0
  90. package/dist/esm/utils/table-access.js +233 -0
  91. package/dist/esm/utils/table-access.js.map +1 -0
  92. package/dist/esm/utils/web-push.d.ts +43 -0
  93. package/dist/esm/utils/web-push.d.ts.map +1 -0
  94. package/dist/esm/utils/web-push.js +59 -0
  95. package/dist/esm/utils/web-push.js.map +1 -0
  96. package/package.json +3 -3
  97. package/src/index.ts +16 -0
  98. package/src/utils/cart-currency.ts +76 -0
  99. package/src/utils/cart-line-pricing.ts +151 -0
  100. package/src/utils/discount-engine.ts +437 -0
  101. package/src/utils/product-options.ts +1150 -0
  102. package/src/utils/rich-text-embeds-codegen.ts +16 -183
  103. package/src/utils/rich-text-embeds-runtime-source.ts +405 -0
  104. package/src/utils/session-cookie-resolver.ts +305 -0
  105. package/src/utils/subscription-access.ts +59 -0
  106. package/src/utils/table-access.ts +516 -0
  107. package/src/utils/web-push.ts +61 -0
@@ -2,59 +2,11 @@
2
2
  * Code-generation helpers for the rich-text embed contract.
3
3
  *
4
4
  * Kept apart from `rich-text-embeds.ts` on purpose: that module is imported by
5
- * the studio editor and the canvas renderer, which are BROWSER bundles, and the
6
- * function registry below holds a live reference to every helper so that none
7
- * of them can be tree-shaken. Only the project generator imports this file.
5
+ * the studio editor and the canvas renderer, which are BROWSER bundles. Only
6
+ * the project generator imports this file.
8
7
  */
9
- import {
10
- CUSTOM_EMBED_PROVIDER_ID,
11
- DEFAULT_EMBED_ALIGN,
12
- DEFAULT_EMBED_SANDBOX_LEVEL,
13
- DEFAULT_EMBED_WIDTH,
14
- EMBED_ALIGNMENTS,
15
- EMBED_ATTR,
16
- EMBED_BLOT_NAME,
17
- EMBED_CAPTION_CLASS_NAME,
18
- EMBED_CAPTION_STYLE,
19
- EMBED_CLASS_NAME,
20
- EMBED_FRAME_CLASS_NAME,
21
- EMBED_HEIGHT_MESSAGE_TYPE,
22
- EMBED_INITIAL_HEIGHT,
23
- EMBED_MAX_HEIGHT,
24
- EMBED_MIN_HEIGHT,
25
- EMBED_PROVIDERS,
26
- EMBED_SANDBOX_DOC_HEAD,
27
- EMBED_SANDBOX_DOC_TAIL,
28
- EMBED_SANDBOX_FLAGS_STRICT,
29
- EMBED_SANDBOX_FLAGS_TRUSTED,
30
- EMBED_TOKEN_PLACEHOLDER,
31
- GENERIC_EMBED_PROVIDER_ID,
32
- WIDESCREEN_EMBED_RATIO,
33
- applyEmbedTemplate,
34
- buildEmbedElementHtml,
35
- buildEmbedFrameChildren,
36
- buildEmbedHtmlFromUrl,
37
- buildEmbedSandboxDocument,
38
- clampEmbedWidth,
39
- createEmbedToken,
40
- createEmbedValue,
41
- decodeEmbedCode,
42
- embedBlockStyle,
43
- embedFrameStyle,
44
- encodeEmbedCode,
45
- escapeEmbedAttribute,
46
- escapeEmbedText,
47
- findEmbedFrame,
48
- isSafeEmbedUrl,
49
- normalizeEmbedAlign,
50
- normalizeEmbedsForStorage,
51
- parseEmbedHeightMessage,
52
- readEmbedValueFromElement,
53
- readEncodedEmbedCode,
54
- resolveEmbedMode,
55
- resolveEmbedProvider,
56
- resolveEmbedSandboxFlags,
57
- } from './rich-text-embeds'
8
+ import { EMBED_PROVIDERS } from './rich-text-embeds'
9
+ import { EMBED_RUNTIME_MODULE_SOURCE } from './rich-text-embeds-runtime-source'
58
10
 
59
11
  /**
60
12
  * The provider registry as a JavaScript literal, so the component the Next
@@ -79,138 +31,19 @@ export function serializeEmbedProvidersForRuntime(): string {
79
31
  return `[\n ${entries.join(',\n ')}\n]`
80
32
  }
81
33
 
82
- /* ── The generated runtime module ───────────────────────────────────────────
83
- *
84
- * The exported project needs these same helpers at runtime: its rich-text
85
- * editor builds embeds with them and its activator mounts them. Rather than
86
- * hand-copying the logic into a code-generator template — where it would drift
87
- * from this file the first time a provider is added — the module is EMITTED
88
- * from the very functions above: the constants are serialized, the functions
89
- * are printed with `Function.prototype.toString`, and the result is written to
90
- * the generated project as `components/embed-runtime.js`.
91
- *
92
- * Two rules keep that safe, and `__tests__/utils/rich-text-embeds.ts` pins both:
93
- * - every emitted function may only reference other emitted functions and the
94
- * constants below, never a module-private helper or an import;
95
- * - the emitted module must parse and behave identically to this one.
96
- */
97
-
98
- /**
99
- * Every function the generated editor and activator reach — the ones they
100
- * import, plus everything those call in turn. Deliberately not the whole of
101
- * `rich-text-embeds`: the editor overlay helpers belong to the studio, and an
102
- * export nothing calls is dead weight in every generated project.
103
- */
104
- const RUNTIME_EXPORTS: Array<(...args: never[]) => unknown> = [
105
- isSafeEmbedUrl,
106
- resolveEmbedProvider,
107
- applyEmbedTemplate,
108
- buildEmbedHtmlFromUrl,
109
- resolveEmbedMode,
110
- clampEmbedWidth,
111
- normalizeEmbedAlign,
112
- escapeEmbedAttribute,
113
- escapeEmbedText,
114
- encodeEmbedCode,
115
- decodeEmbedCode,
116
- createEmbedValue,
117
- embedBlockStyle,
118
- embedFrameStyle,
119
- buildEmbedElementHtml,
120
- buildEmbedFrameChildren,
121
- findEmbedFrame,
122
- readEmbedValueFromElement,
123
- readEncodedEmbedCode,
124
- normalizeEmbedsForStorage,
125
- resolveEmbedSandboxFlags,
126
- buildEmbedSandboxDocument,
127
- parseEmbedHeightMessage,
128
- createEmbedToken,
129
- ]
130
-
131
- interface RuntimeConstant {
132
- name: string
133
- literal: string
134
- }
135
-
136
- const runtimeConstant = (name: string, literal: string): RuntimeConstant => ({ name, literal })
137
-
138
34
  /**
139
- * TypeScript's CommonJS emit rewrites every reference to an exported CONSTANT
140
- * as `exports.NAME` (exported functions keep their bare names, which is why
141
- * they can call each other). The generator runs against that CommonJS build, so
142
- * printed function bodies arrive carrying `exports.` prefixes that mean nothing
143
- * in the emitted module — where each constant is re-declared as a plain
144
- * top-level binding of the same name. Rewriting them back is therefore exact,
145
- * not a heuristic: only names this module emits are rewritten, and
146
- * `generateEmbedRuntimeModuleSource` asserts nothing module-scoped is left.
35
+ * `components/embed-runtime.js` for the generated project: the helpers its
36
+ * rich-text editor builds embeds with and its activator mounts them with.
37
+ *
38
+ * A STRING committed beside this file, not printed from the functions with
39
+ * `Function.prototype.toString` at generation time: teleport-gui runs this
40
+ * generator inside a minified bundle, where the minifier renames every one of
41
+ * those functions and the constants they read, so the emitted module exported
42
+ * none of the names the activator imports. A minifier never rewrites a string
43
+ * literal. `__tests__/utils/rich-text-embeds-runtime-module.ts` fails when the
44
+ * string drifts from `rich-text-embeds.ts` and regenerates it with
45
+ * UPDATE_EMBED_RUNTIME=1.
147
46
  */
148
- const bindRuntimeConstantReferences = (source: string, names: string[]): string =>
149
- names.reduce((acc, name) => acc.replace(new RegExp(`\\bexports\\.${name}\\b`, 'g'), name), source)
150
-
151
47
  export function generateEmbedRuntimeModuleSource(): string {
152
- const constants: RuntimeConstant[] = [
153
- runtimeConstant('EMBED_CLASS_NAME', JSON.stringify(EMBED_CLASS_NAME)),
154
- runtimeConstant('EMBED_FRAME_CLASS_NAME', JSON.stringify(EMBED_FRAME_CLASS_NAME)),
155
- runtimeConstant('EMBED_CAPTION_CLASS_NAME', JSON.stringify(EMBED_CAPTION_CLASS_NAME)),
156
- runtimeConstant('EMBED_BLOT_NAME', JSON.stringify(EMBED_BLOT_NAME)),
157
- runtimeConstant('EMBED_ATTR', JSON.stringify(EMBED_ATTR, null, 2)),
158
- runtimeConstant('EMBED_ALIGNMENTS', JSON.stringify(EMBED_ALIGNMENTS)),
159
- runtimeConstant('CUSTOM_EMBED_PROVIDER_ID', JSON.stringify(CUSTOM_EMBED_PROVIDER_ID)),
160
- runtimeConstant('GENERIC_EMBED_PROVIDER_ID', JSON.stringify(GENERIC_EMBED_PROVIDER_ID)),
161
- runtimeConstant('DEFAULT_EMBED_WIDTH', String(DEFAULT_EMBED_WIDTH)),
162
- runtimeConstant('DEFAULT_EMBED_ALIGN', JSON.stringify(DEFAULT_EMBED_ALIGN)),
163
- runtimeConstant('DEFAULT_EMBED_SANDBOX_LEVEL', JSON.stringify(DEFAULT_EMBED_SANDBOX_LEVEL)),
164
- runtimeConstant('WIDESCREEN_EMBED_RATIO', String(WIDESCREEN_EMBED_RATIO)),
165
- runtimeConstant('EMBED_CAPTION_STYLE', JSON.stringify(EMBED_CAPTION_STYLE)),
166
- runtimeConstant('EMBED_PROVIDERS', serializeEmbedProvidersForRuntime()),
167
- runtimeConstant('EMBED_SANDBOX_FLAGS_STRICT', JSON.stringify(EMBED_SANDBOX_FLAGS_STRICT)),
168
- runtimeConstant('EMBED_SANDBOX_FLAGS_TRUSTED', JSON.stringify(EMBED_SANDBOX_FLAGS_TRUSTED)),
169
- runtimeConstant('EMBED_HEIGHT_MESSAGE_TYPE', JSON.stringify(EMBED_HEIGHT_MESSAGE_TYPE)),
170
- runtimeConstant('EMBED_TOKEN_PLACEHOLDER', JSON.stringify(EMBED_TOKEN_PLACEHOLDER)),
171
- runtimeConstant('EMBED_MIN_HEIGHT', String(EMBED_MIN_HEIGHT)),
172
- runtimeConstant('EMBED_MAX_HEIGHT', String(EMBED_MAX_HEIGHT)),
173
- runtimeConstant('EMBED_INITIAL_HEIGHT', String(EMBED_INITIAL_HEIGHT)),
174
- runtimeConstant('EMBED_SANDBOX_DOC_HEAD', JSON.stringify(EMBED_SANDBOX_DOC_HEAD)),
175
- runtimeConstant('EMBED_SANDBOX_DOC_TAIL', JSON.stringify(EMBED_SANDBOX_DOC_TAIL)),
176
- // `createEmbedToken` closes over this counter.
177
- runtimeConstant('embedTokenCounter', '0'),
178
- ]
179
-
180
- const names = constants.map((entry) => entry.name)
181
- const declarations = constants.map((entry) => `export var ${entry.name} = ${entry.literal}`)
182
- const functions = RUNTIME_EXPORTS.map(
183
- (fn) => `export ${bindRuntimeConstantReferences(fn.toString(), names)}`
184
- )
185
-
186
- const source = `${RUNTIME_MODULE_HEADER}\n${declarations.join('\n\n')}\n\n${functions.join(
187
- '\n\n'
188
- )}\n`
189
-
190
- // An `exports.` reference that survived means a function reached for a
191
- // constant left off the list above. That crashes every generated project at
192
- // runtime, so it fails here instead. (Import leakage is covered by the
193
- // emitted module being evaluated in this package's tests — this module has
194
- // no imports, and must not gain any.)
195
- const leaked = source.match(/\bexports\.[A-Za-z_$][\w$]*/g)
196
- if (leaked) {
197
- throw new Error(
198
- `Embed runtime module cannot be emitted: unresolved module references ${leaked.join(', ')}`
199
- )
200
- }
201
-
202
- return source
48
+ return EMBED_RUNTIME_MODULE_SOURCE
203
49
  }
204
-
205
- const RUNTIME_MODULE_HEADER = `/**
206
- * Code embeds inside rich-text content — the shape the editor writes and the
207
- * page reads back. Generated from @teleporthq/teleport-shared; edit it there.
208
- *
209
- * An embed is stored inside the content HTML as a <figure class="tq-embed">.
210
- * Passive markup (a provider iframe) lives in the figure as real children, so
211
- * it renders server-side with no JavaScript. Markup that can execute — a
212
- * <script>, an on* handler, a javascript: URL — is base64-encoded onto the
213
- * element instead, and mounted at runtime inside a sandboxed iframe so it can
214
- * never reach this page.
215
- */
216
- `
@@ -0,0 +1,405 @@
1
+ // GENERATED from src/utils/rich-text-embeds.ts — do not edit by hand. Regenerate with
2
+ // UPDATE_EMBED_RUNTIME=1 npx jest packages/teleport-shared/__tests__/utils/rich-text-embeds-runtime-module.ts
3
+ // (see generateEmbedRuntimeModuleSource for why this is a string).
4
+ /* tslint:disable:no-invalid-template-strings -- the lines are JavaScript source */
5
+ export const EMBED_RUNTIME_MODULE_SOURCE = [
6
+ '/**',
7
+ ' * Code embeds inside rich-text content — the shape the editor writes and the',
8
+ ' * page reads back. Generated from @teleporthq/teleport-shared; edit it there.',
9
+ ' *',
10
+ ' * An embed is stored inside the content HTML as a <figure class="tq-embed">.',
11
+ ' * Passive markup (a provider iframe) lives in the figure as real children, so',
12
+ ' * it renders server-side with no JavaScript. Markup that can execute — a',
13
+ ' * <script>, an on* handler, a javascript: URL — is base64-encoded onto the',
14
+ ' * element instead, and mounted at runtime inside a sandboxed iframe so it can',
15
+ ' * never reach this page.',
16
+ ' */',
17
+ '',
18
+ 'export var EMBED_CLASS_NAME = "tq-embed"',
19
+ '',
20
+ 'export var EMBED_FRAME_CLASS_NAME = "tq-embed-frame"',
21
+ '',
22
+ 'export var EMBED_CAPTION_CLASS_NAME = "tq-embed-caption"',
23
+ '',
24
+ 'export var EMBED_BLOT_NAME = "tq-embed"',
25
+ '',
26
+ 'export var EMBED_ATTR = {',
27
+ ' "MARKER": "data-tq-embed",',
28
+ ' "PROVIDER": "data-tq-embed-provider",',
29
+ ' "URL": "data-tq-embed-url",',
30
+ ' "MODE": "data-tq-embed-mode",',
31
+ ' "CODE": "data-tq-embed-code",',
32
+ ' "RATIO": "data-tq-embed-ratio",',
33
+ ' "WIDTH": "data-tq-embed-width",',
34
+ ' "ALIGN": "data-tq-embed-align",',
35
+ ' "CAPTION": "data-tq-embed-caption",',
36
+ ' "SANDBOX": "data-tq-embed-sandbox",',
37
+ ' "ACTIVATED": "data-tq-embed-activated",',
38
+ ' "PREVIEW": "data-tq-embed-preview"',
39
+ '}',
40
+ '',
41
+ 'export var EMBED_ALIGNMENTS = ["center","float-left","float-right"]',
42
+ '',
43
+ 'export var CUSTOM_EMBED_PROVIDER_ID = "custom"',
44
+ '',
45
+ 'export var GENERIC_EMBED_PROVIDER_ID = "iframe-url"',
46
+ '',
47
+ 'export var DEFAULT_EMBED_WIDTH = 100',
48
+ '',
49
+ 'export var DEFAULT_EMBED_ALIGN = "center"',
50
+ '',
51
+ 'export var DEFAULT_EMBED_SANDBOX_LEVEL = "strict"',
52
+ '',
53
+ 'export var WIDESCREEN_EMBED_RATIO = 56.25',
54
+ '',
55
+ 'export var EMBED_CAPTION_STYLE = "margin-top:8px;font-size:0.875em;line-height:1.5;opacity:0.75;text-align:center"',
56
+ '',
57
+ 'export var EMBED_PROVIDERS = [',
58
+ ' { id: "youtube", label: "YouTube", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.|m\\\\.)?youtube\\\\.com\\\\/watch\\\\?(?:[^#]*&)?v=([A-Za-z0-9_-]{6,})", "i"), new RegExp("^https?:\\\\/\\\\/youtu\\\\.be\\\\/([A-Za-z0-9_-]{6,})", "i"), new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?youtube\\\\.com\\\\/shorts\\\\/([A-Za-z0-9_-]{6,})", "i"), new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?youtube(?:-nocookie)?\\\\.com\\\\/embed\\\\/([A-Za-z0-9_-]{6,})", "i")], template: "<iframe src=\\"https://www.youtube.com/embed/$1\\" title=\\"YouTube video\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 },',
59
+ ' { id: "vimeo", label: "Vimeo", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?vimeo\\\\.com\\\\/(\\\\d+)", "i"), new RegExp("^https?:\\\\/\\\\/player\\\\.vimeo\\\\.com\\\\/video\\\\/(\\\\d+)", "i")], template: "<iframe src=\\"https://player.vimeo.com/video/$1\\" title=\\"Vimeo video\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 },',
60
+ ' { id: "loom", label: "Loom", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?loom\\\\.com\\\\/(?:share|embed)\\\\/([A-Za-z0-9]+)", "i")], template: "<iframe src=\\"https://www.loom.com/embed/$1\\" title=\\"Loom video\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 },',
61
+ ' { id: "dailymotion", label: "Dailymotion", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?dailymotion\\\\.com\\\\/video\\\\/([A-Za-z0-9]+)", "i"), new RegExp("^https?:\\\\/\\\\/dai\\\\.ly\\\\/([A-Za-z0-9]+)", "i")], template: "<iframe src=\\"https://www.dailymotion.com/embed/video/$1\\" title=\\"Dailymotion video\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 },',
62
+ ' { id: "spotify", label: "Spotify", patterns: [new RegExp("^https?:\\\\/\\\\/open\\\\.spotify\\\\.com\\\\/(?:embed\\\\/)?(track|album|playlist|episode|show|artist)\\\\/([A-Za-z0-9]+)", "i")], template: "<iframe src=\\"https://open.spotify.com/embed/$1/$2\\" title=\\"Spotify player\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:352px\\"></iframe>", ratio: null },',
63
+ ' { id: "soundcloud", label: "SoundCloud", patterns: [new RegExp("^https?:\\\\/\\\\/soundcloud\\\\.com\\\\/[^?#]+", "i")], template: "<iframe src=\\"https://w.soundcloud.com/player/?url=$E&&color=%23ff5500&auto_play=false&show_teaser=false\\" title=\\"SoundCloud player\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:166px\\"></iframe>", ratio: null },',
64
+ ' { id: "apple-podcasts", label: "Apple Podcasts", patterns: [new RegExp("^https?:\\\\/\\\\/podcasts\\\\.apple\\\\.com\\\\/(.+)$", "i")], template: "<iframe src=\\"https://embed.podcasts.apple.com/$1\\" title=\\"Apple Podcasts player\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:175px\\"></iframe>", ratio: null },',
65
+ ' { id: "twitter", label: "X (Twitter)", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?(?:twitter|x)\\\\.com\\\\/[^/]+\\\\/status\\\\/(\\\\d+)", "i")], template: "<blockquote class=\\"twitter-tweet\\"><a href=\\"$&\\"></a></blockquote><script async src=\\"https://platform.twitter.com/widgets.js\\" charset=\\"utf-8\\"></script>", ratio: null },',
66
+ ' { id: "instagram", label: "Instagram", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?instagram\\\\.com\\\\/(?:p|reel|tv)\\\\/([A-Za-z0-9_-]+)", "i")], template: "<blockquote class=\\"instagram-media\\" data-instgrm-permalink=\\"https://www.instagram.com/p/$1/\\" data-instgrm-version=\\"14\\"></blockquote><script async src=\\"https://www.instagram.com/embed.js\\"></script>", ratio: null },',
67
+ ' { id: "tiktok", label: "TikTok", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?tiktok\\\\.com\\\\/@[^/]+\\\\/video\\\\/(\\\\d+)", "i")], template: "<blockquote class=\\"tiktok-embed\\" cite=\\"$&\\" data-video-id=\\"$1\\"><section></section></blockquote><script async src=\\"https://www.tiktok.com/embed.js\\"></script>", ratio: null },',
68
+ ' { id: "reddit", label: "Reddit", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?reddit\\\\.com\\\\/r\\\\/[^/]+\\\\/comments\\\\/.+", "i")], template: "<blockquote class=\\"reddit-embed-bq\\"><a href=\\"$&\\"></a></blockquote><script async src=\\"https://embed.reddit.com/widgets.js\\" charset=\\"UTF-8\\"></script>", ratio: null },',
69
+ ' { id: "pinterest", label: "Pinterest", patterns: [new RegExp("^https?:\\\\/\\\\/(?:[a-z]{2}\\\\.)?pinterest\\\\.[a-z.]+\\\\/pin\\\\/[0-9]+", "i")], template: "<a data-pin-do=\\"embedPin\\" href=\\"$&\\"></a><script async defer src=\\"https://assets.pinterest.com/js/pinit.js\\"></script>", ratio: null },',
70
+ ' { id: "facebook", label: "Facebook", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.|web\\\\.)?facebook\\\\.com\\\\/.+\\\\/(?:posts|videos)\\\\/.+", "i")], template: "<iframe src=\\"https://www.facebook.com/plugins/post.php?href=$E&&show_text=true\\" title=\\"Facebook post\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:500px\\"></iframe>", ratio: null },',
71
+ ' { id: "github-gist", label: "GitHub Gist", patterns: [new RegExp("^https?:\\\\/\\\\/gist\\\\.github\\\\.com\\\\/([^/]+\\\\/[a-f0-9]+)", "i")], template: "<script src=\\"https://gist.github.com/$1.js\\"></script>", ratio: null },',
72
+ ' { id: "codepen", label: "CodePen", patterns: [new RegExp("^https?:\\\\/\\\\/codepen\\\\.io\\\\/([^/]+)\\\\/(?:pen|embed|details|full)\\\\/([A-Za-z0-9]+)", "i")], template: "<iframe src=\\"https://codepen.io/$1/embed/$2?default-tab=result\\" title=\\"CodePen\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:400px\\"></iframe>", ratio: null },',
73
+ ' { id: "codesandbox", label: "CodeSandbox", patterns: [new RegExp("^https?:\\\\/\\\\/codesandbox\\\\.io\\\\/(?:s|embed)\\\\/([A-Za-z0-9_-]+)", "i"), new RegExp("^https?:\\\\/\\\\/codesandbox\\\\.io\\\\/p\\\\/(?:sandbox|devbox)\\\\/([A-Za-z0-9_-]+)", "i")], template: "<iframe src=\\"https://codesandbox.io/embed/$1\\" title=\\"CodeSandbox\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:500px\\"></iframe>", ratio: null },',
74
+ ' { id: "jsfiddle", label: "JSFiddle", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?jsfiddle\\\\.net\\\\/((?:[^/]+\\\\/)?[A-Za-z0-9]+)\\\\/?", "i")], template: "<iframe src=\\"https://jsfiddle.net/$1/embedded/\\" title=\\"JSFiddle\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:400px\\"></iframe>", ratio: null },',
75
+ ' { id: "figma", label: "Figma", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?figma\\\\.com\\\\/(?:file|design|proto|board|slides)\\\\/.+", "i")], template: "<iframe src=\\"https://www.figma.com/embed?embed_host=share&url=$E&\\" title=\\"Figma\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 },',
76
+ ' { id: "canva", label: "Canva", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?canva\\\\.com\\\\/design\\\\/([A-Za-z0-9_-]+)\\\\/([A-Za-z0-9_-]+)\\\\/(?:view|watch)", "i")], template: "<iframe src=\\"https://www.canva.com/design/$1/$2/view?embed\\" title=\\"Canva design\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 },',
77
+ ' { id: "miro", label: "Miro", patterns: [new RegExp("^https?:\\\\/\\\\/miro\\\\.com\\\\/app\\\\/(?:board|live-embed)\\\\/([A-Za-z0-9_=-]+)", "i")], template: "<iframe src=\\"https://miro.com/app/live-embed/$1/\\" title=\\"Miro board\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 },',
78
+ ' { id: "google-maps", label: "Google Maps", patterns: [new RegExp("^https?:\\\\/\\\\/(?:www\\\\.)?google\\\\.[a-z.]+\\\\/maps\\\\/embed\\\\?(.+)$", "i")], template: "<iframe src=\\"https://www.google.com/maps/embed?$1\\" title=\\"Google Maps\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 },',
79
+ ' { id: "google-maps-place", label: "Google Maps", patterns: [new RegExp("^https?:\\\\/\\\\/(?:(?:www\\\\.)?google\\\\.[a-z.]+\\\\/maps|maps\\\\.app\\\\.goo\\\\.gl)\\\\/.+", "i")], template: "<iframe src=\\"https://maps.google.com/maps?q=$E&&output=embed\\" title=\\"Google Maps\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 },',
80
+ ' { id: "google-forms", label: "Google Forms", patterns: [new RegExp("^https?:\\\\/\\\\/docs\\\\.google\\\\.com\\\\/forms\\\\/d\\\\/(?:e\\\\/)?([A-Za-z0-9_-]+)", "i")], template: "<iframe src=\\"https://docs.google.com/forms/d/e/$1/viewform?embedded=true\\" title=\\"Google Form\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:700px\\"></iframe>", ratio: null },',
81
+ ' { id: "google-docs", label: "Google Docs", patterns: [new RegExp("^https?:\\\\/\\\\/docs\\\\.google\\\\.com\\\\/(document|spreadsheets|presentation)\\\\/d\\\\/([A-Za-z0-9_-]+)", "i")], template: "<iframe src=\\"https://docs.google.com/$1/d/$2/preview\\" title=\\"Google Docs\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:600px\\"></iframe>", ratio: null },',
82
+ ' { id: "airtable", label: "Airtable", patterns: [new RegExp("^https?:\\\\/\\\\/airtable\\\\.com\\\\/(?:embed\\\\/)?(app[A-Za-z0-9/?=&_-]+)", "i")], template: "<iframe src=\\"https://airtable.com/embed/$1\\" title=\\"Airtable\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:533px\\"></iframe>", ratio: null },',
83
+ ' { id: "typeform", label: "Typeform", patterns: [new RegExp("^https?:\\\\/\\\\/(?:[A-Za-z0-9-]+\\\\.)?typeform\\\\.com\\\\/to\\\\/([A-Za-z0-9]+)", "i")], template: "<iframe src=\\"https://form.typeform.com/to/$1\\" title=\\"Typeform\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:500px\\"></iframe>", ratio: null },',
84
+ ' { id: "calendly", label: "Calendly", patterns: [new RegExp("^https?:\\\\/\\\\/calendly\\\\.com\\\\/(.+)$", "i")], template: "<iframe src=\\"https://calendly.com/$1\\" title=\\"Calendly\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"display:block;width:100%;border:0;border-radius:inherit;height:700px\\"></iframe>", ratio: null },',
85
+ ' { id: "iframe-url", label: "Web page", patterns: [new RegExp("^https:\\\\/\\\\/[^\\\\s\\"\'<>]+$", "i")], template: "<iframe src=\\"$&\\" title=\\"Embedded page\\" loading=\\"lazy\\" frameborder=\\"0\\" referrerpolicy=\\"strict-origin-when-cross-origin\\" allow=\\"accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share\\" allowfullscreen style=\\"position:absolute;top:0;left:0;width:100%;height:100%;border:0;border-radius:inherit\\"></iframe>", ratio: 56.25 }',
86
+ ']',
87
+ '',
88
+ 'export var EMBED_SANDBOX_FLAGS_STRICT = "allow-scripts allow-popups allow-popups-to-escape-sandbox allow-forms allow-presentation"',
89
+ '',
90
+ 'export var EMBED_SANDBOX_FLAGS_TRUSTED = "allow-scripts allow-popups allow-popups-to-escape-sandbox allow-forms allow-presentation allow-same-origin"',
91
+ '',
92
+ 'export var EMBED_HEIGHT_MESSAGE_TYPE = "tq-embed-height"',
93
+ '',
94
+ 'export var EMBED_TOKEN_PLACEHOLDER = "__TQ_EMBED_TOKEN__"',
95
+ '',
96
+ 'export var EMBED_MIN_HEIGHT = 80',
97
+ '',
98
+ 'export var EMBED_MAX_HEIGHT = 6000',
99
+ '',
100
+ 'export var EMBED_INITIAL_HEIGHT = 320',
101
+ '',
102
+ 'export var EMBED_SANDBOX_DOC_HEAD = "<!doctype html><html><head><meta charset=\\"utf-8\\"><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1\\"><base target=\\"_blank\\"><style>html,body{margin:0;padding:0;background:transparent}img,iframe,video,blockquote{max-width:100%}</style><script>(function(){var token=\\"__TQ_EMBED_TOKEN__\\";var last=0;function report(){try{var doc=document.documentElement;var body=document.body;var height=Math.max(doc?doc.scrollHeight:0,doc?doc.offsetHeight:0,body?body.scrollHeight:0,body?body.offsetHeight:0);if(!height||height===last){return;}last=height;parent.postMessage({type:\\"tq-embed-height\\",token:token,height:height},\\"*\\");}catch(e){}}function watch(){report();if(typeof ResizeObserver===\\"function\\"&&document.documentElement){new ResizeObserver(report).observe(document.documentElement);}if(typeof MutationObserver===\\"function\\"&&document.body){new MutationObserver(report).observe(document.body,{childList:true,subtree:true,attributes:true});}var delays=[150,400,900,1800,3500];for(var i=0;i<delays.length;i++){setTimeout(report,delays[i]);}}if(document.readyState===\\"loading\\"){document.addEventListener(\\"DOMContentLoaded\\",watch);}else{watch();}window.addEventListener(\\"load\\",report);})();</script></head><body>"',
103
+ '',
104
+ 'export var EMBED_SANDBOX_DOC_TAIL = "</body></html>"',
105
+ '',
106
+ 'export var embedTokenCounter = 0',
107
+ '',
108
+ 'export function isSafeEmbedUrl(url) {',
109
+ " return /^https?:\\/\\/[^\\s\"'<>]+$/i.test((url || '').trim());",
110
+ '}',
111
+ '',
112
+ 'export function resolveEmbedProvider(url) {',
113
+ " const trimmed = (url || '').trim();",
114
+ ' if (!isSafeEmbedUrl(trimmed)) {',
115
+ ' return null;',
116
+ ' }',
117
+ ' for (const provider of EMBED_PROVIDERS) {',
118
+ ' for (const pattern of provider.patterns) {',
119
+ ' const match = trimmed.match(pattern);',
120
+ ' if (match) {',
121
+ ' return { provider, match };',
122
+ ' }',
123
+ ' }',
124
+ ' }',
125
+ ' return null;',
126
+ '}',
127
+ '',
128
+ 'export function applyEmbedTemplate(template, match, url) {',
129
+ ' return template.replace(/\\$(\\$|E?(?:[1-9]|&))/g, (_token, spec) => {',
130
+ ' var _a;',
131
+ " if (spec === '$') {",
132
+ " return '$';",
133
+ ' }',
134
+ " const encoded = spec.charAt(0) === 'E';",
135
+ ' const key = encoded ? spec.slice(1) : spec;',
136
+ " const raw = key === '&' ? url : (_a = match[Number(key)]) !== null && _a !== void 0 ? _a : '';",
137
+ ' return encoded ? encodeURIComponent(raw) : raw;',
138
+ ' });',
139
+ '}',
140
+ '',
141
+ 'export function buildEmbedHtmlFromUrl(url) {',
142
+ ' const resolved = resolveEmbedProvider(url);',
143
+ ' if (!resolved) {',
144
+ ' return null;',
145
+ ' }',
146
+ ' return {',
147
+ ' provider: resolved.provider,',
148
+ ' html: applyEmbedTemplate(resolved.provider.template, resolved.match, url.trim()),',
149
+ ' };',
150
+ '}',
151
+ '',
152
+ 'export function resolveEmbedMode(html) {',
153
+ " const markup = html || '';",
154
+ ' const executes = /<script[\\s/>]/i.test(markup) ||',
155
+ ' /\\son[a-z]+\\s*=/i.test(markup) ||',
156
+ ' /(?:href|src|action|formaction)\\s*=\\s*["\']?\\s*javascript:/i.test(markup);',
157
+ " return executes ? 'sandbox' : 'inline';",
158
+ '}',
159
+ '',
160
+ 'export function clampEmbedWidth(width) {',
161
+ ' if (!isFinite(width)) {',
162
+ ' return DEFAULT_EMBED_WIDTH;',
163
+ ' }',
164
+ ' return Math.max(10, Math.min(100, Math.round(width)));',
165
+ '}',
166
+ '',
167
+ 'export function normalizeEmbedAlign(align) {',
168
+ ' return EMBED_ALIGNMENTS.indexOf(align) !== -1',
169
+ ' ? align',
170
+ ' : DEFAULT_EMBED_ALIGN;',
171
+ '}',
172
+ '',
173
+ 'export function escapeEmbedAttribute(value) {',
174
+ " return String(value !== null && value !== void 0 ? value : '')",
175
+ " .replace(/&/g, '&amp;')",
176
+ " .replace(/\"/g, '&quot;')",
177
+ " .replace(/</g, '&lt;')",
178
+ " .replace(/>/g, '&gt;');",
179
+ '}',
180
+ '',
181
+ 'export function escapeEmbedText(value) {',
182
+ " return String(value !== null && value !== void 0 ? value : '')",
183
+ " .replace(/&/g, '&amp;')",
184
+ " .replace(/</g, '&lt;')",
185
+ " .replace(/>/g, '&gt;');",
186
+ '}',
187
+ '',
188
+ 'export function encodeEmbedCode(code) {',
189
+ ' const binary = encodeURIComponent(code).replace(/%([0-9A-F]{2})/gi, (_m, hex) => String.fromCharCode(parseInt(hex, 16)));',
190
+ " if (typeof btoa === 'function') {",
191
+ ' return btoa(binary);',
192
+ ' }',
193
+ " if (typeof Buffer !== 'undefined') {",
194
+ " return Buffer.from(binary, 'binary').toString('base64');",
195
+ ' }',
196
+ " throw new Error('No base64 encoder available');",
197
+ '}',
198
+ '',
199
+ 'export function decodeEmbedCode(encoded) {',
200
+ ' let binary;',
201
+ " if (typeof atob === 'function') {",
202
+ ' binary = atob(encoded);',
203
+ ' }',
204
+ " else if (typeof Buffer !== 'undefined') {",
205
+ " binary = Buffer.from(encoded, 'base64').toString('binary');",
206
+ ' }',
207
+ ' else {',
208
+ " throw new Error('No base64 decoder available');",
209
+ ' }',
210
+ " let percent = '';",
211
+ ' for (let index = 0; index < binary.length; index += 1) {',
212
+ ' percent += `%${`00${binary.charCodeAt(index).toString(16)}`.slice(-2)}`;',
213
+ ' }',
214
+ ' return decodeURIComponent(percent);',
215
+ '}',
216
+ '',
217
+ 'export function createEmbedValue(params) {',
218
+ ' var _a, _b, _c;',
219
+ " const code = params.code || '';",
220
+ ' return {',
221
+ ' provider: params.provider || CUSTOM_EMBED_PROVIDER_ID,',
222
+ " url: params.url || '',",
223
+ ' code,',
224
+ ' mode: resolveEmbedMode(code),',
225
+ ' ratio: (_a = params.ratio) !== null && _a !== void 0 ? _a : null,',
226
+ ' width: clampEmbedWidth((_b = params.width) !== null && _b !== void 0 ? _b : DEFAULT_EMBED_WIDTH),',
227
+ ' align: normalizeEmbedAlign((_c = params.align) !== null && _c !== void 0 ? _c : DEFAULT_EMBED_ALIGN),',
228
+ " caption: params.caption || '',",
229
+ " sandboxLevel: params.sandboxLevel === 'trusted' ? 'trusted' : DEFAULT_EMBED_SANDBOX_LEVEL,",
230
+ ' };',
231
+ '}',
232
+ '',
233
+ 'export function embedBlockStyle(value) {',
234
+ ' const declarations = [',
235
+ " 'position:relative',",
236
+ ' `width:${clampEmbedWidth(value.width)}%`,',
237
+ " 'max-width:100%',",
238
+ " 'margin:16px 0',",
239
+ ' ];',
240
+ " if (value.align === 'center') {",
241
+ " declarations.push('margin-left:auto', 'margin-right:auto');",
242
+ ' }',
243
+ " else if (value.align === 'float-left') {",
244
+ " declarations.push('float:left', 'margin-right:16px', 'margin-bottom:8px');",
245
+ ' }',
246
+ " else if (value.align === 'float-right') {",
247
+ " declarations.push('float:right', 'margin-left:16px', 'margin-bottom:8px');",
248
+ ' }',
249
+ " return declarations.join(';');",
250
+ '}',
251
+ '',
252
+ 'export function embedFrameStyle(ratio) {',
253
+ ' if (ratio === null || !isFinite(ratio) || ratio <= 0) {',
254
+ " return 'position:relative;width:100%';",
255
+ ' }',
256
+ ' return `position:relative;width:100%;padding-top:${ratio}%`;',
257
+ '}',
258
+ '',
259
+ 'export function buildEmbedElementHtml(value) {',
260
+ ' const attrs = [',
261
+ ' `class="${EMBED_CLASS_NAME}"`,',
262
+ ' `${EMBED_ATTR.MARKER}="1"`,',
263
+ ' `${EMBED_ATTR.PROVIDER}="${escapeEmbedAttribute(value.provider)}"`,',
264
+ ' `${EMBED_ATTR.MODE}="${value.mode}"`,',
265
+ ' `${EMBED_ATTR.WIDTH}="${clampEmbedWidth(value.width)}"`,',
266
+ ' `${EMBED_ATTR.ALIGN}="${value.align}"`,',
267
+ ' `${EMBED_ATTR.SANDBOX}="${value.sandboxLevel}"`,',
268
+ ' ];',
269
+ ' if (value.url) {',
270
+ ' attrs.push(`${EMBED_ATTR.URL}="${escapeEmbedAttribute(value.url)}"`);',
271
+ ' }',
272
+ ' if (value.ratio !== null) {',
273
+ ' attrs.push(`${EMBED_ATTR.RATIO}="${value.ratio}"`);',
274
+ ' }',
275
+ ' if (value.caption) {',
276
+ ' attrs.push(`${EMBED_ATTR.CAPTION}="${escapeEmbedAttribute(value.caption)}"`);',
277
+ ' }',
278
+ " if (value.mode === 'sandbox') {",
279
+ ' attrs.push(`${EMBED_ATTR.CODE}="${escapeEmbedAttribute(encodeEmbedCode(value.code))}"`);',
280
+ ' }',
281
+ ' attrs.push(\'contenteditable="false"\');',
282
+ ' attrs.push(`style="${embedBlockStyle(value)}"`);',
283
+ ' const caption = value.caption',
284
+ ' ? `<figcaption class="${EMBED_CAPTION_CLASS_NAME}" style="${EMBED_CAPTION_STYLE}">${escapeEmbedText(value.caption)}</figcaption>`',
285
+ " : '';",
286
+ " return (`<figure ${attrs.join(' ')}>` +",
287
+ ' `<div class="${EMBED_FRAME_CLASS_NAME}" style="${embedFrameStyle(value.ratio)}">` +',
288
+ ' `${buildEmbedFrameChildren(value)}</div>${caption}</figure>`);',
289
+ '}',
290
+ '',
291
+ 'export function buildEmbedFrameChildren(value) {',
292
+ " if (value.mode === 'inline') {",
293
+ ' return value.code;',
294
+ ' }',
295
+ ' if (!value.url) {',
296
+ " return '';",
297
+ ' }',
298
+ ' return (`<noscript><a href="${escapeEmbedAttribute(value.url)}" rel="noopener noreferrer" ` +',
299
+ ' `target="_blank">${escapeEmbedText(value.url)}</a></noscript>`);',
300
+ '}',
301
+ '',
302
+ 'export function findEmbedFrame(element) {',
303
+ ' return element.querySelector(`.${EMBED_FRAME_CLASS_NAME}`);',
304
+ '}',
305
+ '',
306
+ 'export function readEmbedValueFromElement(element) {',
307
+ " const mode = element.getAttribute(EMBED_ATTR.MODE) === 'sandbox' ? 'sandbox' : 'inline';",
308
+ ' const frame = findEmbedFrame(element);',
309
+ ' const rawRatio = element.getAttribute(EMBED_ATTR.RATIO);',
310
+ ' const parsedRatio = rawRatio === null ? NaN : parseFloat(rawRatio);',
311
+ " let code = '';",
312
+ " if (mode === 'sandbox') {",
313
+ ' code = readEncodedEmbedCode(element);',
314
+ ' }',
315
+ ' else if (frame) {',
316
+ ' code = frame.innerHTML;',
317
+ ' }',
318
+ ' return {',
319
+ ' provider: element.getAttribute(EMBED_ATTR.PROVIDER) || CUSTOM_EMBED_PROVIDER_ID,',
320
+ " url: element.getAttribute(EMBED_ATTR.URL) || '',",
321
+ ' code,',
322
+ ' mode,',
323
+ ' ratio: isFinite(parsedRatio) ? parsedRatio : null,',
324
+ " width: clampEmbedWidth(parseFloat(element.getAttribute(EMBED_ATTR.WIDTH) || '')),",
325
+ " align: normalizeEmbedAlign(element.getAttribute(EMBED_ATTR.ALIGN) || ''),",
326
+ " caption: element.getAttribute(EMBED_ATTR.CAPTION) || '',",
327
+ " sandboxLevel: element.getAttribute(EMBED_ATTR.SANDBOX) === 'trusted'",
328
+ " ? 'trusted'",
329
+ ' : DEFAULT_EMBED_SANDBOX_LEVEL,',
330
+ ' };',
331
+ '}',
332
+ '',
333
+ 'export function readEncodedEmbedCode(element) {',
334
+ ' const encoded = element.getAttribute(EMBED_ATTR.CODE);',
335
+ ' if (!encoded) {',
336
+ " return '';",
337
+ ' }',
338
+ ' try {',
339
+ ' return decodeEmbedCode(encoded);',
340
+ ' }',
341
+ ' catch (_a) {',
342
+ " return '';",
343
+ ' }',
344
+ '}',
345
+ '',
346
+ 'export function normalizeEmbedsForStorage(root) {',
347
+ ' const previews = root.querySelectorAll(`[${EMBED_ATTR.PREVIEW}]`);',
348
+ ' for (let index = previews.length - 1; index >= 0; index -= 1) {',
349
+ ' const preview = previews[index];',
350
+ ' if (preview.parentNode) {',
351
+ ' preview.parentNode.removeChild(preview);',
352
+ ' }',
353
+ ' }',
354
+ ' const blocks = root.querySelectorAll(`[${EMBED_ATTR.MARKER}]`);',
355
+ ' for (let index = 0; index < blocks.length; index += 1) {',
356
+ ' const block = blocks[index];',
357
+ ' block.removeAttribute(EMBED_ATTR.ACTIVATED);',
358
+ ' const frame = findEmbedFrame(block);',
359
+ ' if (!frame) {',
360
+ ' continue;',
361
+ ' }',
362
+ ' const value = readEmbedValueFromElement(block);',
363
+ " if (value.mode !== 'sandbox') {",
364
+ ' continue;',
365
+ ' }',
366
+ ' frame.innerHTML = buildEmbedFrameChildren(value);',
367
+ ' }',
368
+ '}',
369
+ '',
370
+ 'export function resolveEmbedSandboxFlags(level) {',
371
+ " return level === 'trusted' ? EMBED_SANDBOX_FLAGS_TRUSTED : EMBED_SANDBOX_FLAGS_STRICT;",
372
+ '}',
373
+ '',
374
+ 'export function buildEmbedSandboxDocument(code, token) {',
375
+ ' return (EMBED_SANDBOX_DOC_HEAD.replace(EMBED_TOKEN_PLACEHOLDER, token) +',
376
+ " (code || '') +",
377
+ ' EMBED_SANDBOX_DOC_TAIL);',
378
+ '}',
379
+ '',
380
+ 'export function parseEmbedHeightMessage(data) {',
381
+ " if (!data || typeof data !== 'object') {",
382
+ ' return null;',
383
+ ' }',
384
+ ' const message = data;',
385
+ " if (message.type !== EMBED_HEIGHT_MESSAGE_TYPE || typeof message.token !== 'string') {",
386
+ ' return null;',
387
+ ' }',
388
+ ' const height = Number(message.height);',
389
+ ' if (!isFinite(height) || height <= 0) {',
390
+ ' return null;',
391
+ ' }',
392
+ ' return {',
393
+ ' token: message.token,',
394
+ ' height: Math.min(Math.max(Math.round(height), EMBED_MIN_HEIGHT), EMBED_MAX_HEIGHT),',
395
+ ' };',
396
+ '}',
397
+ '',
398
+ 'export function createEmbedToken() {',
399
+ ' embedTokenCounter += 1;',
400
+ ' return `tqe-${Date.now().toString(36)}-${embedTokenCounter.toString(36)}-${Math.random()',
401
+ ' .toString(36)',
402
+ ' .slice(2, 8)}`;',
403
+ '}',
404
+ '',
405
+ ].join('\n')