@tightknitai/block-kitchen 0.10.11 → 0.10.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helpers.cjs +39 -4
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.js +39 -4
- package/dist/helpers.js.map +1 -1
- package/dist/index.cjs +113 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +113 -47
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1838,6 +1838,7 @@ function groupValidatorErrors(errors, blocks) {
|
|
|
1838
1838
|
var SAFE_LINK_PROTOCOLS = /^(https?|ircs?|mailto|tel|sms|xmpp)$/i;
|
|
1839
1839
|
var SAFE_IMAGE_PROTOCOLS = /^(https?)$/i;
|
|
1840
1840
|
var SAFE_IMAGE_DATA_PREFIX = /^data:image\/(?:png|jpeg|jpg|gif|webp|avif|x-icon|vnd\.microsoft\.icon)(?:;[a-z0-9-]+(?:=[^,;]*)?)*,/i;
|
|
1841
|
+
var SAFE_EMBED_PROTOCOLS = /^(https?)$/i;
|
|
1841
1842
|
function getScheme(value) {
|
|
1842
1843
|
const trimmed = value.replace(/^\s+/, "");
|
|
1843
1844
|
const colon = trimmed.indexOf(":");
|
|
@@ -1893,16 +1894,47 @@ function isSafeImageSrc(value) {
|
|
|
1893
1894
|
}
|
|
1894
1895
|
return SAFE_IMAGE_PROTOCOLS.test(scheme);
|
|
1895
1896
|
}
|
|
1897
|
+
function isSafeEmbedSrc(value) {
|
|
1898
|
+
if (typeof value !== "string") {
|
|
1899
|
+
return false;
|
|
1900
|
+
}
|
|
1901
|
+
if (value.length === 0) {
|
|
1902
|
+
return true;
|
|
1903
|
+
}
|
|
1904
|
+
const scheme = getScheme(value);
|
|
1905
|
+
if (scheme === null) {
|
|
1906
|
+
return false;
|
|
1907
|
+
}
|
|
1908
|
+
return SAFE_EMBED_PROTOCOLS.test(scheme);
|
|
1909
|
+
}
|
|
1896
1910
|
function sanitizeHref(value) {
|
|
1897
1911
|
return isSafeHref(value) ? value ?? "" : "";
|
|
1898
1912
|
}
|
|
1899
1913
|
function sanitizeImageSrc(value) {
|
|
1900
1914
|
return isSafeImageSrc(value) ? value ?? "" : "";
|
|
1901
1915
|
}
|
|
1916
|
+
function sanitizeEmbedSrc(value) {
|
|
1917
|
+
return isSafeEmbedSrc(value) ? value ?? "" : "";
|
|
1918
|
+
}
|
|
1902
1919
|
|
|
1903
1920
|
// src/lib/sanitize-blocks.ts
|
|
1904
|
-
var
|
|
1905
|
-
var
|
|
1921
|
+
var EMBED_KEYS = /* @__PURE__ */ new Set(["video_url"]);
|
|
1922
|
+
var URL_KEY = /(^|_)(url|uri|link|href|src)$/;
|
|
1923
|
+
var MAYBE_URL_KEY = /url|uri|link|href|src/i;
|
|
1924
|
+
var IMAGE_KEY_HINT = /image|thumb|icon|avatar|logo|photo|picture/;
|
|
1925
|
+
function classifyUrlKey(key) {
|
|
1926
|
+
if (!MAYBE_URL_KEY.test(key)) {
|
|
1927
|
+
return null;
|
|
1928
|
+
}
|
|
1929
|
+
const normalized = key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
1930
|
+
if (EMBED_KEYS.has(normalized)) {
|
|
1931
|
+
return "embed";
|
|
1932
|
+
}
|
|
1933
|
+
if (!URL_KEY.test(normalized)) {
|
|
1934
|
+
return null;
|
|
1935
|
+
}
|
|
1936
|
+
return IMAGE_KEY_HINT.test(normalized) ? "image" : "href";
|
|
1937
|
+
}
|
|
1906
1938
|
var RETRIEVAL_ONLY_KEYS = /* @__PURE__ */ new Map([
|
|
1907
1939
|
// Covers both the image block and the image element — both `type: 'image'`.
|
|
1908
1940
|
["image", /* @__PURE__ */ new Set(["image_width", "image_height", "image_bytes", "fallback", "is_animated"])],
|
|
@@ -1938,10 +1970,13 @@ function sanitizeValue(value) {
|
|
|
1938
1970
|
const original = src[key];
|
|
1939
1971
|
let next = original;
|
|
1940
1972
|
if (typeof original === "string") {
|
|
1941
|
-
|
|
1973
|
+
const kind = classifyUrlKey(key);
|
|
1974
|
+
if (kind === "href") {
|
|
1942
1975
|
next = sanitizeHref(original);
|
|
1943
|
-
} else if (
|
|
1976
|
+
} else if (kind === "image") {
|
|
1944
1977
|
next = sanitizeImageSrc(original);
|
|
1978
|
+
} else if (kind === "embed") {
|
|
1979
|
+
next = sanitizeEmbedSrc(original);
|
|
1945
1980
|
}
|
|
1946
1981
|
} else if (typeof original === "object" && original !== null) {
|
|
1947
1982
|
next = sanitizeValue(original);
|
|
@@ -3254,6 +3289,7 @@ function ChannelCombobox({
|
|
|
3254
3289
|
)
|
|
3255
3290
|
] });
|
|
3256
3291
|
}
|
|
3292
|
+
var EMBED_SELECTOR = "iframe[src], embed[src], object[data], source[src], video[src], audio[src], track[src]";
|
|
3257
3293
|
function SlackBlockPreview({
|
|
3258
3294
|
block,
|
|
3259
3295
|
hooks,
|
|
@@ -3286,6 +3322,13 @@ function SlackBlockPreview({
|
|
|
3286
3322
|
img.setAttribute("data-bk-blocked-src", "1");
|
|
3287
3323
|
}
|
|
3288
3324
|
}
|
|
3325
|
+
for (const el of root.querySelectorAll(EMBED_SELECTOR)) {
|
|
3326
|
+
const attr = el.tagName === "OBJECT" ? "data" : "src";
|
|
3327
|
+
if (!isSafeEmbedSrc(el.getAttribute(attr))) {
|
|
3328
|
+
el.removeAttribute(attr);
|
|
3329
|
+
el.setAttribute("data-bk-blocked-src", "1");
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3289
3332
|
});
|
|
3290
3333
|
return (
|
|
3291
3334
|
// The library scopes all of its CSS under `#slack_blocks_to_jsx` and
|
|
@@ -9138,7 +9181,14 @@ function SourcesField({
|
|
|
9138
9181
|
] })
|
|
9139
9182
|
] });
|
|
9140
9183
|
}
|
|
9184
|
+
function UnsafeUrlNote({ children }) {
|
|
9185
|
+
return /* @__PURE__ */ jsx("p", { className: "mt-1 text-[11px] text-destructive", children });
|
|
9186
|
+
}
|
|
9141
9187
|
function VideoEditor({ block, onChange }) {
|
|
9188
|
+
const videoUrlIsUnsafe = (block.video_url ?? "").length > 0 && !isSafeEmbedSrc(block.video_url);
|
|
9189
|
+
const thumbnailIsUnsafe = (block.thumbnail_url ?? "").length > 0 && !isSafeImageSrc(block.thumbnail_url);
|
|
9190
|
+
const titleUrlIsUnsafe = (block.title_url ?? "").length > 0 && !isSafeHref(block.title_url);
|
|
9191
|
+
const providerIconIsUnsafe = (block.provider_icon_url ?? "").length > 0 && !isSafeImageSrc(block.provider_icon_url);
|
|
9142
9192
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
9143
9193
|
/* @__PURE__ */ jsx(EditorField, { label: "Title", help: "Up to 199 characters. Shown above the embedded player.", htmlFor: "video-title", children: /* @__PURE__ */ jsx(
|
|
9144
9194
|
Input,
|
|
@@ -9162,50 +9212,62 @@ function VideoEditor({ block, onChange }) {
|
|
|
9162
9212
|
onChange: (e) => onChange({ ...block, alt_text: e.target.value })
|
|
9163
9213
|
}
|
|
9164
9214
|
) }),
|
|
9165
|
-
/* @__PURE__ */
|
|
9215
|
+
/* @__PURE__ */ jsxs(
|
|
9166
9216
|
EditorField,
|
|
9167
9217
|
{
|
|
9168
9218
|
label: "Video URL",
|
|
9169
9219
|
help: "HTTPS embed URL. Must match an unfurl domain on your Slack app.",
|
|
9170
9220
|
htmlFor: "video-url",
|
|
9171
|
-
children:
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9221
|
+
children: [
|
|
9222
|
+
/* @__PURE__ */ jsx(
|
|
9223
|
+
Input,
|
|
9224
|
+
{
|
|
9225
|
+
id: "video-url",
|
|
9226
|
+
type: "url",
|
|
9227
|
+
value: block.video_url ?? "",
|
|
9228
|
+
placeholder: "e.g. https://www.youtube.com/embed/dQw4w9WgXcQ",
|
|
9229
|
+
onChange: (e) => onChange({ ...block, video_url: e.target.value }),
|
|
9230
|
+
"aria-invalid": videoUrlIsUnsafe || void 0
|
|
9231
|
+
}
|
|
9232
|
+
),
|
|
9233
|
+
videoUrlIsUnsafe && /* @__PURE__ */ jsx(UnsafeUrlNote, { children: "The embedded player only accepts a full http(s) URL. This URL will be stripped before send and preview." })
|
|
9234
|
+
]
|
|
9181
9235
|
}
|
|
9182
9236
|
),
|
|
9183
|
-
/* @__PURE__ */
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9237
|
+
/* @__PURE__ */ jsxs(EditorField, { label: "Thumbnail URL", help: "Preview image shown before the video loads.", htmlFor: "video-thumbnail", children: [
|
|
9238
|
+
/* @__PURE__ */ jsx(
|
|
9239
|
+
Input,
|
|
9240
|
+
{
|
|
9241
|
+
id: "video-thumbnail",
|
|
9242
|
+
type: "url",
|
|
9243
|
+
value: block.thumbnail_url ?? "",
|
|
9244
|
+
placeholder: "e.g. https://example.com/thumb.png",
|
|
9245
|
+
onChange: (e) => onChange({ ...block, thumbnail_url: e.target.value }),
|
|
9246
|
+
"aria-invalid": thumbnailIsUnsafe || void 0
|
|
9247
|
+
}
|
|
9248
|
+
),
|
|
9249
|
+
thumbnailIsUnsafe && /* @__PURE__ */ jsx(UnsafeUrlNote, { children: "Only http(s) image URLs are allowed. This URL will be stripped before send and preview." })
|
|
9250
|
+
] }),
|
|
9251
|
+
/* @__PURE__ */ jsxs(
|
|
9194
9252
|
EditorField,
|
|
9195
9253
|
{
|
|
9196
9254
|
label: "Title link URL",
|
|
9197
9255
|
help: "Optional. HTTPS link the title text opens (the non-embed page).",
|
|
9198
9256
|
htmlFor: "video-title-url",
|
|
9199
|
-
children:
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9257
|
+
children: [
|
|
9258
|
+
/* @__PURE__ */ jsx(
|
|
9259
|
+
Input,
|
|
9260
|
+
{
|
|
9261
|
+
id: "video-title-url",
|
|
9262
|
+
type: "url",
|
|
9263
|
+
value: block.title_url ?? "",
|
|
9264
|
+
placeholder: "e.g. https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
|
9265
|
+
onChange: (e) => onChange({ ...block, title_url: e.target.value || void 0 }),
|
|
9266
|
+
"aria-invalid": titleUrlIsUnsafe || void 0
|
|
9267
|
+
}
|
|
9268
|
+
),
|
|
9269
|
+
titleUrlIsUnsafe && /* @__PURE__ */ jsx(UnsafeUrlNote, { children: "Only http(s), mailto, tel, sms, and xmpp links are allowed. This URL will be stripped before send and preview." })
|
|
9270
|
+
]
|
|
9209
9271
|
}
|
|
9210
9272
|
),
|
|
9211
9273
|
/* @__PURE__ */ jsx(EditorField, { label: "Description", help: "Optional. Up to 199 characters.", htmlFor: "video-description", children: /* @__PURE__ */ jsx(
|
|
@@ -9249,22 +9311,26 @@ function VideoEditor({ block, onChange }) {
|
|
|
9249
9311
|
)
|
|
9250
9312
|
}
|
|
9251
9313
|
),
|
|
9252
|
-
/* @__PURE__ */
|
|
9314
|
+
/* @__PURE__ */ jsxs(
|
|
9253
9315
|
EditorField,
|
|
9254
9316
|
{
|
|
9255
9317
|
label: "Provider icon URL",
|
|
9256
9318
|
help: "Optional. Small icon shown next to the provider name.",
|
|
9257
9319
|
htmlFor: "video-provider-icon",
|
|
9258
|
-
children:
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
|
|
9266
|
-
|
|
9267
|
-
|
|
9320
|
+
children: [
|
|
9321
|
+
/* @__PURE__ */ jsx(
|
|
9322
|
+
Input,
|
|
9323
|
+
{
|
|
9324
|
+
id: "video-provider-icon",
|
|
9325
|
+
type: "url",
|
|
9326
|
+
value: block.provider_icon_url ?? "",
|
|
9327
|
+
placeholder: "e.g. https://example.com/youtube-favicon.png",
|
|
9328
|
+
onChange: (e) => onChange({ ...block, provider_icon_url: e.target.value || void 0 }),
|
|
9329
|
+
"aria-invalid": providerIconIsUnsafe || void 0
|
|
9330
|
+
}
|
|
9331
|
+
),
|
|
9332
|
+
providerIconIsUnsafe && /* @__PURE__ */ jsx(UnsafeUrlNote, { children: "Only http(s) image URLs are allowed. This URL will be stripped before send and preview." })
|
|
9333
|
+
]
|
|
9268
9334
|
}
|
|
9269
9335
|
)
|
|
9270
9336
|
] });
|