UNPKG

notion-helper

Version:

A library of functions for working more easily with the Notion API

1,551 lines (1,547 loc) 149 kB
// src/constants.mjs var CONSTANTS = { MAX_TEXT_LENGTH: 2e3, MAX_BLOCKS: 100, MAX_BLOCKS_REQEST: 999, MAX_CHILD_ARRAY_DEPTH: 2, MAX_PAYLOAD_SIZE: 45e4, // 450kb IMAGE_SUPPORT: { FORMATS: [ "bmp", "gif", "heic", "jpeg", "jpg", "png", "svg", "tif", "tiff" ] }, VIDEO_SUPPORT: { FORMATS: [ "amv", "asf", "avi", "f4v", "flv", "gifv", "mkv", "mov", "mpg", "mpeg", "mpv", "mp4", "m4v", "qt", "wmv" ], SITES: [ "youtube.com" ] }, AUDIO_SUPPORT: { FORMATS: [ "mp3", "wav", "ogg", "mid", "midi", "wma", "aac", "m4a", "m4b" ] }, DOCUMENT_SUPPORT: { FORMATS: [ "pdf", "json", "txt" ] } }; var constants_default = CONSTANTS; // src/utils.mjs function isSingleEmoji(string) { const trimmedString = string.trim(); const regex = /^(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)(?:\p{Emoji_Modifier})?$/u; return regex.test(trimmedString); } function isValidURL(string) { try { const url2 = new URL(string); return url2.protocol === "http:" || url2.protocol === "https:"; } catch (e) { return false; } } function isValidUUID(string) { const regex = /^[0-9a-fA-F]{8}(-?[0-9a-fA-F]{4}){3}-?[0-9a-fA-F]{12}$/; return regex.test(string); } function validateImageURL(url2) { try { const supportedFormats = constants_default.IMAGE_SUPPORT.FORMATS.join("|"); const formatRegex = new RegExp(`\\.(${supportedFormats})$`, "i"); return formatRegex.test(url2) && isValidURL(url2); } catch (e) { return false; } } function validateVideoURL(url2) { try { const supportedFormats = constants_default.VIDEO_SUPPORT.FORMATS.join("|"); const formatRegex = new RegExp(`\\.(${supportedFormats})$`, "i"); const supportedSites = constants_default.VIDEO_SUPPORT.SITES.join("|"); const siteRegex = new RegExp(`(${supportedSites})`, "i"); return (formatRegex.test(url2) || siteRegex.test(url2)) && isValidURL(url2); } catch (e) { return false; } } function validateAudioURL(url2) { try { const supportedFormats = constants_default.AUDIO_SUPPORT.FORMATS.join("|"); const formatRegex = new RegExp(`\\.(${supportedFormats})$`, "i"); return formatRegex.test(url2) && isValidURL(url2); } catch (e) { return false; } } function validatePDFURL(url2) { try { const formatRegex = new RegExp(`\\.pdf$`, "i"); return formatRegex.test(url2) && isValidURL(url2); } catch (e) { return false; } } function enforceStringLength(string, limit) { if (typeof string !== "string") { console.error( "Invalid input sent to enforceStringLength(). Expected a string, got: ", string, typeof string ); throw new Error("Invalid input: Expected a string."); } const charLimit = constants_default.MAX_TEXT_LENGTH; const softLimit = limit && limit > 0 ? limit : charLimit * 0.8; if (string.length < charLimit) { return [string]; } else { let chunks = []; let currentIndex = 0; while (currentIndex < string.length) { let nextCutIndex = Math.min( currentIndex + softLimit, string.length ); let nextSpaceIndex = string.indexOf(" ", nextCutIndex); if (nextSpaceIndex === -1 || nextSpaceIndex - currentIndex > softLimit) { nextSpaceIndex = nextCutIndex; } while (nextSpaceIndex > 0 && string.charCodeAt(nextSpaceIndex - 1) >= 55296 && string.charCodeAt(nextSpaceIndex - 1) <= 56319) { nextSpaceIndex--; } chunks.push(string.substring(currentIndex, nextSpaceIndex)); currentIndex = nextSpaceIndex + 1; } return chunks; } } function validateDate(dateInput) { let date2; if (dateInput === null) { return null; } if (dateInput instanceof Date) { date2 = dateInput; } else if (typeof dateInput === "string") { date2 = new Date(dateInput); } else { console.warn(`Invalid input: Expected a Date object or string representing a date. Returning null.`); return null; } if (!isNaN(date2.getTime())) { const isoString = date2.toISOString(); if (typeof dateInput === "string" && !dateInput.includes(":") && !dateInput.includes("T")) { return isoString.split("T")[0]; } else { return isoString; } } else { console.warn(`Invalid date string or Date object provided. Returning null.`); return null; } } function getDepth(arr, level = 0) { if (!Array.isArray(arr) || arr.length === 0) { return level; } let maxDepth = level; for (let block2 of arr) { if (block2[block2.type].children) { const depth = getDepth(block2[block2.type].children, level + 1); maxDepth = Math.max(maxDepth, depth); } } return maxDepth; } function getTotalCount(arr) { if (!arr || arr?.length === 0) return 0; return arr.reduce( (acc, child) => { if (child[child.type].children) { return acc + 1 + getTotalCount(child[child.type].children); } return acc; }, 0 ); } function getLongestArray(arr, count = 0) { if (!Array.isArray(arr) || arr.length === 0) { return count; } let maxLength = Math.max(count, arr.length); for (let block2 of arr) { if (block2[block2.type].children) { const count2 = getLongestArray(block2[block2.type].children, maxLength); maxLength = Math.max(count2, maxLength); } } return maxLength; } function getPayloadSize(arr) { if (!arr || !Array.isArray(arr)) return 0; const size = arr.reduce((acc, block2) => { return acc + new TextEncoder().encode(JSON.stringify(block2)).length; }, 0); return size; } // src/rich-text.mjs function buildRichTextObj(input, options = {}) { if (arguments.length > 1 && !options.url && !options.type && !options.annotations) { options = { annotations: arguments[1], url: arguments[2], type: arguments[3] || "text" }; } const { annotations = {}, url: url2, type = "text" } = options; if (typeof input === "string") { switch (type) { case "text": return [ { type: "text", text: { content: input, link: url2 ? { url: url2 } : null }, annotations: { ...annotations } } ]; case "equation": return [ { type: "equation", equation: { expression: input } } ]; } } if (typeof input === "object") { if (type === "text" || !type) { return [ { type: "text", text: input } ]; } else { switch (type) { case "equation": return [ { type: "equation", equation: input, annotations: { ...annotations } } ]; case "mention": return [ { type: "mention", mention: input, annotations: { ...annotations } } ]; default: const error2 = `Unsupported rich text type: ${input.type}`; console.error(error2); throw new Error(error2); } } } const error = `Invalid input send to buildRichTextObj()`; console.error(error); throw new Error(error); } function enforceRichText(content) { if (!content) { return []; } if (Array.isArray(content)) { return content.flatMap( (item) => typeof item === "string" ? enforceRichText(item) : enforceRichTextObject(item) ); } if (typeof content === "string") { const strings = enforceStringLength(content); const richTextObjects = strings.flatMap((string) => { const isURL = isValidURL(string); const isBold = /^\*{2}[\s\S]*?\*{2}$/.test(string); const isItalic = /^[\*_]{1}[^\*_]{1}[\s\S]*?[^\*_]{1}[\*_]{1}$/.test(string); const isBoldItalic = /^\*{3}[\s\S]*?\*{3}$/.test(string); let plainString = string; if (isBold || isItalic || isBoldItalic) { plainString = string.replace(/^(\*|_)+|(\*|_)+$/g, ""); } return buildRichTextObj( plainString, { annotations: { bold: isBold || isBoldItalic, italic: isItalic || isBoldItalic }, url: isURL ? plainString : null } ); }); return richTextObjects; } if (typeof content === "number") { return buildRichTextObj(content.toString()); } if (typeof content === "object") { return [enforceRichTextObject(content)]; } console.warn(`Invalid input for rich text. Returning empty array.`); return []; } function enforceRichTextObject(obj) { if (typeof obj === "string") { return buildRichTextObj(obj)[0]; } if (obj.type && obj.text && typeof obj.text.content === "string") { return obj; } console.warn(`Invalid rich text object. Returning empty rich text object.`); return buildRichTextObj("")[0]; } // src/emoji-and-files.mjs function setIcon(value) { if (typeof value !== "string") { return {}; } const isEmoji = isSingleEmoji(value); const isImageURL = validateImageURL(value); const isUUID = isValidUUID(value); if (isImageURL) { return createExternal(value); } else if (isEmoji) { return createEmoji(value); } else if (isUUID) { return createFile(value); } else { return void 0; } } function createExternal(url2) { return { type: "external", external: { url: url2 } }; } function createEmoji(emoji) { return { type: "emoji", emoji }; } function createFile(id) { return { type: "file_upload", file_upload: { id } }; } // src/blocks.mjs var block = { /** * Methods for audio blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ audio: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: false, /** * Creates an audio block. * * @function * @param {string|Object} options - A string representing the audio URL, a file upload ID, or an options object. * @param {string} options.url - The URL for the audio. * @param {string} options.id - The ID of the file upload. * @param {string|string[]|Array<Object>} [options.caption=[]] - The caption as a string, an array of strings, or an array of rich text objects. * @returns {Object|null} An audio block object compatible with Notion's API, or null if the URL/ID is invalid. * @example * // Use with an external URL * const externalAudio = block.audio.createBlock("https://thomasjfrank.com/wp-content/uploads/2025/05/output3.mp3"); * * // Use with a file upload ID * const fileUploadAudio = block.audio.createBlock("123e4567-e89b-12d3-a456-426614174000"); * * // Use with options object for external audio * const externalAudio = block.audio.createBlock({ * url: "https://thomasjfrank.com/wp-content/uploads/2025/05/output3.mp3", * caption: "Check out my mixtape, man." * }); * * // Use with options object for file upload * const fileUploadAudio = block.audio.createBlock({ * id: "123e4567-e89b-12d3-a456-426614174000", * caption: "Check out my mixtape, man." * }); */ createBlock: (options) => { let url2, id, caption; if (typeof options === "string") { url2 = options; caption = []; } else { ({ url: url2, id, caption = [] } = options); } let urlOrId = url2 || id; const isValidAudio = validateAudioURL(urlOrId) || isValidUUID(urlOrId); const isFileUpload = isValidUUID(urlOrId); const isExternal = isValidURL(urlOrId); const audioType = isFileUpload ? "file_upload" : isExternal ? "external" : "file"; if (!isValidAudio) { console.warn(`${urlOrId} is not a valid audio URL or file upload ID.`); } return isValidAudio ? { type: "audio", audio: { type: audioType, [audioType]: { [audioType === "file_upload" ? "id" : "url"]: urlOrId }, caption: enforceRichText(caption) } } : null; } }, /** * Methods for bookmark blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ bookmark: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: false, /** * Creates a bookmark block. * * @function * @param {string|Object} options - A string representing the URL, or an options object. * @param {string} options.url - The URL to be bookmarked. * @param {string|string[]|Array<Object>} [options.caption=[]] - The caption as a string, an array of strings, or an array of rich text objects. * @returns {Object} A bookmark block object compatible with Notion's API. * @example * // Use with just a URL * const simpleBookmark = block.bookmark.createBlock("https://www.flylighter.com"); * * // Use with options object * const complexBookmark = block.bookmark.createBlock({ * url: "https://www.flylighter.com", * caption: "Flylighter is a super-rad web clipper for Notion." * }); * * // Use with options object and array of strings for caption * const multiLineBookmark = block.bookmark.createBlock({ * url: "https://www.flylighter.com", * caption: ["Flylighter is a web clipper for Notion...", "...and Obsidian, too."] * }); */ createBlock: (options) => { let url2, caption; if (typeof options === "string") { url2 = options; caption = []; } else { ({ url: url2, caption = [] } = options); } return { type: "bookmark", bookmark: { url: url2, caption: enforceRichText(caption) } }; } }, /** * Methods for breadcrumb blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ breadcrumb: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: false, /** * Creates a breadcrumb block. * * @returns {Object} A breadcrumb block object. * * @example * // Create a breadcrumb block * const breadcrumbBlock = block.breadcrumb.createBlock(); */ createBlock: () => { return { type: "breadcrumb", breadcrumb: {} }; } }, /** * Methods for bulleted list item blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ bulleted_list_item: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a bulleted list item block. * * @function * @param {string|string[]|Object} options - A string, an array of strings, or an options object representing the list item content. * @param {string|string[]|Array<Object>} [options.rich_text=[]] - The item's content as a string, an array of strings, or an array of rich text objects. * @param {Array<Object>} [options.children=[]] - An array of child block objects. * @param {string} [options.color="default"] - Color for the text. * @returns {Object} A bulleted list item block object compatible with Notion's API. * @example * // Use with a string * const simpleItem = block.bulleted_list_item.createBlock("Simple list item"); * * // Use with an array of strings * const multiLineItem = block.bulleted_list_item.createBlock(["Line 1", "Line 2"]); * * // Use with options object * const complexItem = block.bulleted_list_item.createBlock({ * rich_text: "Complex item", * color: "red", * children: [ * // Child blocks would go here * ] * }); */ createBlock: (options) => { let rich_text, children, color; if (typeof options === "string" || Array.isArray(options)) { rich_text = options; children = []; color = "default"; } else { ({ rich_text = [], children = [], color = "default" } = options); } return { type: "bulleted_list_item", bulleted_list_item: { rich_text: enforceRichText(rich_text), color, ...children.length > 0 && { children } } }; } }, /** * Methods for callout blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ callout: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a callout block. * * @function * @param {string|string[]|Object} options - A string, an array of strings, or an options object representing the callout content. * @param {string|string[]|Array<Object>} [options.rich_text=[]] - The content as a string, an array of strings, or an array of rich text objects. * @param {string} [options.icon=""] - An optional icon value (URL for "external" or emoji character for "emoji"). * @param {Array<Object>} [options.children=[]] - An array of child block objects. * @param {string} [options.color="default"] - Color for the callout background. * @returns {Object} A callout block object compatible with Notion's API. * @example * // Use with a string * const simpleCallout = block.callout.createBlock("I though I told you never to come in here, McFly!"); * * // Use with options object * const complexCallout = block.callout.createBlock({ * rich_text: "Now make like a tree and get outta here.", * icon: "💡", * color: "blue_background", * children: [ * // Child blocks would go here * ] * }); */ createBlock: (options) => { let rich_text, icon2, children, color; if (typeof options === "string" || Array.isArray(options)) { rich_text = options; icon2 = ""; children = []; color = "default"; } else { ({ rich_text = [], icon: icon2 = "", children = [], color = "default" } = options); } return { type: "callout", callout: { rich_text: enforceRichText(rich_text), icon: setIcon(icon2), color, ...children.length > 0 && { children } } }; } }, /** * Methods for code blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ code: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: false, /** * Creates a code block. * * @function * @param {string|Object} options - A string representing the code content, or an options object. * @param {string|string[]|Array<Object>} [options.rich_text=[]] - The code content as a string, an array of strings, or an array of rich text objects. * @param {string|string[]|Array<Object>} [options.caption=[]] - The caption as a string, an array of strings, or an array of rich text objects. * @param {string} [options.language="plain text"] - Programming language of the code block. * @returns {Object} A code block object compatible with Notion's API. * @example * // Use with a string * const simpleCode = block.code.createBlock("console.log('Give me all the bacon and eggs you have.');"); * * // Use with options object * const complexCode = block.code.createBlock({ * rich_text: "const name = 'Monkey D. Luffy'\n console.log(`My name is ${name} and I will be king of the pirates!`)", * language: "JavaScript", * caption: "A simple JavaScript greeting function" * }); */ createBlock: (options) => { let rich_text, caption, language; if (typeof options === "string") { rich_text = options; caption = []; language = "plain text"; } else { ({ rich_text = [], caption = [], language = "plain text" } = options); } return { type: "code", code: { rich_text: enforceRichText(rich_text), caption: enforceRichText(caption), language } }; } }, /** * Methods for column list blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ column_list: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a column list block. Column list blocks must have at least two column child blocks, each of which must have at least one child block - otherwise, the Notion API will throw an error. * * @see https://developers.notion.com/reference/block#column-list-and-column * * @param {(number|Array|undefined)} options - The options for creating the column list block. * @param {number} [options] - The number of columns to create. Each will contain an empty paragraph block. * @param {Array} [options] - An array where each element represents a column. Each element can be: * - A column object (will be added to the final column list's children array directly) * - A string (will create a column object containing a paragraph block with the string's value) * - An array (will create a column object containing the elements as children. Each element should be a string or a valid block object. Strings will be converted to paragraph blocks.) * * @returns {Object|null} The created column list block object, or null if invalid input is provided. * * @example * // Create a column list with 3 empty columns * const emptyColumns = block.column_list.createBlock(3); * * @example * // Create a column list with 2 columns, each containing a paragraph * const twoColumnList = block.column_list.createBlock(["First column", "Second column"]); * * @example * // Create a column list with mixed content * const mixedColumnList = block.column_list.createBlock([ * "Text in first column", * ["Paragraph 1 in second column", "Paragraph 2 in second column"], * { * type: "column", * column: {}, * children: [block.heading_2.createBlock("Custom heading in third column")] * } * ]); * * @example * // Create an empty column list * const emptyColumnList = block.column_list.createBlock(); */ createBlock: (options) => { if (typeof options === "string" || typeof options === "function") { return null; } if (!options || Array.isArray(options) && options.length === 0 || typeof options === "object" && Object.keys(options).length < 1) { return { type: "column_list", column_list: {} }; } if (typeof options === "number") { let columns = []; for (let i = 0; i < options; i++) { const column2 = { type: "column", column: { children: [block.paragraph.createBlock("")] } }; columns.push(column2); } return { type: "column_list", column_list: { children: columns } }; } if (Array.isArray(options)) { let columns = []; for (let option of options) { if (typeof option === "object" && option.hasOwnProperty("column")) { columns.push(option); } if (Array.isArray(option)) { let blocks = []; for (let singleBlock of option) { if (typeof singleBlock === "string") { const paragraph2 = block.paragraph.createBlock(singleBlock); blocks.push(paragraph2); } else if (typeof singleBlock === "object" && singleBlock !== null && !singleBlock.hasOwnProperty("column")) { blocks.push(singleBlock); } } const column2 = { type: "column", column: { children: blocks } }; columns.push(column2); } if (typeof option === "string") { const column2 = { type: "column", column: { children: [block.paragraph.createBlock(option)] } }; columns.push(column2); } if (!Array.isArray(option) && typeof option === "object" && !option.hasOwnProperty("column")) { const column2 = { type: "column", column: { children: [option] } }; columns.push(column2); } } return { type: "column_list", column_list: { children: columns } }; } } }, /** * Methods for column blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ column: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a column block. A column block must have at least one non-column block in its children array, and the column block itself must be appended as a child block to a column_list block. * * @see https://developers.notion.com/reference/block#column-list-and-column * * @param {(Array|string|undefined)} options - The options for creating the column block. * @param {Array} [options] - An array where each element becomes a child block of the column. Each element should be: * - A block object (will be added directly to the column's children array) * - A string (will be converted to a paragraph block) * @param {string} [options] - A string that will be converted into a paragraph block within the column. * * @returns {Object} The created column block object. * * @example * // Create an empty column * const emptyColumn = block.column.createBlock(); * * @example * // Create a column with a single paragraph * const singleParagraphColumn = block.column.createBlock("This is a paragraph in a column"); * * @example * // Create a column with multiple blocks * const multiBlockColumn = block.column.createBlock([ * "First paragraph", * block.heading_2.createBlock("Heading in column"), * "Another paragraph" * ]); * * @example * // Create a column with custom blocks * const customBlocksColumn = block.column.createBlock([ * block.paragraph.createBlock("Custom paragraph"), * block.bulleted_list_item.createBlock("Bullet point in column"), * block.image.createBlock({ url: "https://example.com/image.jpg" }) * ]); */ createBlock: (options) => { if (!options || Array.isArray(options) && options.length === 0 || typeof options === "object" && Object.keys(options).length < 1) { return { type: "column", column: { children: [] } }; } if (typeof options === "string") { return { type: "column", column: { children: [block.paragraph.createBlock(options)] } }; } if (Array.isArray(options)) { let blocks = []; for (let singleBlock of options) { if (typeof singleBlock === "string") { const paragraph2 = block.paragraph.createBlock(singleBlock); blocks.push(paragraph2); } else if (typeof singleBlock === "object" && singleBlock !== null && !singleBlock.hasOwnProperty("column")) { blocks.push(singleBlock); } } return { type: "column", column: { children: blocks } }; } } }, /** * Methods for divider blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ divider: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: false, /** * Creates a divider block. * * @function * @returns {Object} A divider block object compatible with Notion's API. * @example * const divider = block.divider.createBlock(); */ createBlock: () => ({ type: "divider", divider: {} }) }, /** * Methods for embed blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ embed: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: false, /** * Creates an embed block. * * @function * @param {string|Object} options - A string representing the URL to be embedded, or an options object. * @param {string} options.url - The URL to be embedded. * @returns {Object} An embed block object compatible with Notion's API. * @example * // Use with a string * const simpleEmbed = block.embed.createBlock("https://www.youtube.com/watch?v=ec5m6t77eYM"); * * // Use with options object * const complexEmbed = block.embed.createBlock({ * url: "https://www.youtube.com/watch?v=ec5m6t77eYM" * }); */ createBlock: (options) => { const url2 = typeof options === "string" ? options : options.url; return { type: "embed", embed: { url: url2 } }; } }, /** * Methods for file blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ file: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: false, /** * Creates a file block. * * @function * @param {string|Object} options - A string representing the file URL, a file upload ID, or an options object. * @param {string} options.url - The URL for the file. * @param {string} options.id - The ID of the file upload. * @param {string} [options.name] - The name of the file. * @param {string|string[]|Array<Object>} [options.caption=[]] - The caption as a string, an array of strings, or an array of rich text objects. * @returns {Object|null} A file block object compatible with Notion's API, or null if the URL/ID is invalid. * @example * // Use with a file URL * const externalFile = block.file.createBlock("https://collegeinfogeek.com/wp-content/uploads/2015/01/10steps-reddit.pdf"); * * // Use with a file upload ID * const fileUploadFile = block.file.createBlock("123e4567-e89b-12d3-a456-426614174000"); * * // Use with options object for external file * const externalFile = block.file.createBlock({ * url: "https://collegeinfogeek.com/wp-content/uploads/2015/01/10steps-reddit.pdf", * name: "10 Steps to Earning Awesome Grades (preview)", * caption: "The Reddit preview of the 10 Steps to Earning Awesome Grades book." * }); * * // Use with options object for file upload * const fileUploadFile = block.file.createBlock({ * id: "123e4567-e89b-12d3-a456-426614174000", * name: "10 Steps to Earning Awesome Grades (preview)", * caption: "The Reddit preview of the 10 Steps to Earning Awesome Grades book." * }); */ createBlock: (options) => { let url2, id, name, caption; if (typeof options === "string") { url2 = options; name = ""; caption = []; } else { ({ url: url2, id, name = "", caption = [] } = options); } let urlOrId = url2 || id; const isValid = isValidURL(urlOrId) || isValidUUID(urlOrId); const isFileUpload = isValidUUID(urlOrId); const isExternal = isValidURL(urlOrId); const fileType = isFileUpload ? "file_upload" : isExternal ? "external" : "file"; if (!isValid) { console.warn(`${urlOrId} is not a valid file URL or file upload ID.`); } return isValid ? { type: "file", file: { type: fileType, [fileType]: { [fileType === "file_upload" ? "id" : "url"]: urlOrId }, caption: enforceRichText(caption), name: name && name !== "" ? name : void 0 } } : null; } }, /** * Methods for heading_1 blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ heading_1: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a heading_1 block. * * Adding children will coerce headings to toggle headings. * * @function * @param {string|string[]|Object} options - A string, an array of strings, or an options object representing the heading content. * @param {string|string[]|Array<Object>} [options.rich_text=[]] - The content as a string, an array of strings, or an array of rich text objects. * @param {string} [options.color="default"] - Color for the heading text. * @param {boolean} [options.is_toggleable=false] - Whether the heading is toggleable. * @param {Array<Object>} [options.children=[]] - An array of child block objects. * @returns {Object} A heading_1 block object compatible with Notion's API. * @example * // Use with a string * const simpleHeading = block.heading_1.createBlock("Simple Heading"); * * // Use with options object * const complexHeading = block.heading_1.createBlock({ * rich_text: "Complex Heading", * color: "red", * is_toggleable: true, * children: [ * // Child blocks would go here * ] * }); */ createBlock: (options) => { let rich_text, color, is_toggleable, children; if (typeof options === "string" || Array.isArray(options)) { rich_text = options; color = "default"; is_toggleable = false; children = []; } else { ({ rich_text = [], color = "default", is_toggleable = false, children = [] } = options); } return { type: "heading_1", heading_1: { rich_text: enforceRichText(rich_text), color, is_toggleable, ...children.length > 0 && { children } } }; } }, /** * Methods for heading_2 blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ heading_2: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a heading_2 block. * * Adding children will coerce headings to toggle headings. * * @function * @param {string|string[]|Object} options - A string, an array of strings, or an options object representing the heading content. * @param {string|string[]|Array<Object>} [options.rich_text=[]] - The content as a string, an array of strings, or an array of rich text objects. * @param {string} [options.color="default"] - Color for the heading text. * @param {boolean} [options.is_toggleable=false] - Whether the heading is toggleable. * @param {Array<Object>} [options.children=[]] - An array of child block objects. * @returns {Object} A heading_2 block object compatible with Notion's API. * @example * // Use with a string * const simpleHeading = block.heading_2.createBlock("Simple Heading"); * * // Use with options object * const complexHeading = block.heading_2.createBlock({ * rich_text: "Complex Heading", * color: "red", * is_toggleable: true, * children: [ * // Child blocks would go here * ] * }); */ createBlock: (options) => { let rich_text, color, is_toggleable, children; if (typeof options === "string" || Array.isArray(options)) { rich_text = options; color = "default"; is_toggleable = false; children = []; } else { ({ rich_text = [], color = "default", is_toggleable = false, children = [] } = options); } return { type: "heading_2", heading_2: { rich_text: enforceRichText(rich_text), color, is_toggleable, ...children.length > 0 && { children } } }; } }, /** * Methods for heading_3 blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ heading_3: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a heading_3 block. * * Adding children will coerce headings to toggle headings. * * @function * @param {string|string[]|Object} options - A string, an array of strings, or an options object representing the heading content. * @param {string|string[]|Array<Object>} [options.rich_text=[]] - The content as a string, an array of strings, or an array of rich text objects. * @param {string} [options.color="default"] - Color for the heading text. * @param {boolean} [options.is_toggleable=false] - Whether the heading is toggleable. * @param {Array<Object>} [options.children=[]] - An array of child block objects. * @returns {Object} A heading_3 block object compatible with Notion's API. * @example * // Use with a string * const simpleHeading = block.heading_3.createBlock("Simple Heading"); * * // Use with options object * const complexHeading = block.heading_3.createBlock({ * rich_text: "Complex Heading", * color: "red", * is_toggleable: true, * children: [ * // Child blocks would go here * ] * }); */ createBlock: (options) => { let rich_text, color, is_toggleable, children; if (typeof options === "string" || Array.isArray(options)) { rich_text = options; color = "default"; is_toggleable = false; children = []; } else { ({ rich_text = [], color = "default", is_toggleable = false, children = [] } = options); } return { type: "heading_3", heading_3: { rich_text: enforceRichText(rich_text), color, is_toggleable, ...children.length > 0 && { children } } }; } }, /** * Methods for image blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ image: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: false, /** * Creates an image block. * * @function * @param {string|Object} options - A string representing the image URL, a file upload ID, or an options object. * @param {string} options.url - The URL for the image. * @param {string} options.id - The ID of the file upload. * @param {string|string[]|Array<Object>} [options.caption=[]] - The caption as a string, an array of strings, or an array of rich text objects. * @returns {Object|null} An image block object compatible with Notion's API, or null if the URL/ID is invalid. * @example * // Use with a string * const simpleImage = block.image.createBlock("https://i.imgur.com/5vSShIw.jpeg"); * * // Use with a file upload ID * const fileUploadImage = block.image.createBlock("123e4567-e89b-12d3-a456-426614174000"); * * // Use with options object for external image * const complexImage = block.image.createBlock({ * url: "https://i.imgur.com/5vSShIw.jpeg", * caption: "A beautiful landscape" * }); * * // Use with options object for file upload * const fileUploadImage = block.image.createBlock({ * id: "123e4567-e89b-12d3-a456-426614174000", * caption: "A beautiful landscape" * }); */ createBlock: (options) => { let url2, id, caption; if (typeof options === "string") { url2 = options; caption = []; } else { ({ url: url2, id, caption = [] } = options); } let urlOrId = url2 || id; const isValidImage = validateImageURL(urlOrId) || isValidUUID(urlOrId); const isFileUpload = isValidUUID(urlOrId); const isExternal = isValidURL(urlOrId); const imageType = isFileUpload ? "file_upload" : isExternal ? "external" : "file"; if (!isValidImage) { console.warn(`${urlOrId} is not a valid image URL or file upload ID.`); } return isValidImage ? { type: "image", image: { type: imageType, [imageType]: { [imageType === "file_upload" ? "id" : "url"]: urlOrId }, caption: enforceRichText(caption) } } : null; } }, /** * Methods for numbered list item blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ numbered_list_item: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a numbered list item block. * * @function * @param {string|string[]|Object} options - A string, an array of strings, or an options object representing the list item content. * @param {string|string[]|Array<Object>} [options.rich_text=[]] - The content as a string, an array of strings, or an array of rich text objects. * @param {Array<Object>} [options.children=[]] - An array of child block objects. * @param {string} [options.color="default"] - Color for the text. * @returns {Object} A numbered list item block object compatible with Notion's API. * @example * // Use with a string * const simpleItem = block.numbered_list_item.createBlock("Simple list item"); * * // Use with an array of strings * const multiLineItem = block.numbered_list_item.createBlock(["Line 1", "Line 2"]); * * // Use with options object * const complexItem = block.numbered_list_item.createBlock({ * rich_text: "Complex item", * color: "red", * children: [ * // Child blocks would go here * ] * }); */ createBlock: (options) => { let rich_text, children, color; if (typeof options === "string" || Array.isArray(options)) { rich_text = options; children = []; color = "default"; } else { ({ rich_text = [], children = [], color = "default" } = options); } return { type: "numbered_list_item", numbered_list_item: { rich_text: enforceRichText(rich_text), color, ...children.length > 0 && { children } } }; } }, /** * Methods for paragraph blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ paragraph: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a paragraph block. * * @function * @param {string|string[]|Object} options - A string, an array of strings, or an options object representing the paragraph content. * @param {string|string[]|Array<Object>} [options.rich_text=[]] - The content as a string, an array of strings, or an array of rich text objects. * @param {Array<Object>} [options.children=[]] - An array of child block objects. * @param {string} [options.color="default"] - Color for the text. * @returns {Object} A paragraph block object compatible with Notion's API. * @example * // Direct use with a string * const paragraphBlock = block.paragraph.createBlock("Hello, World!"); * * // Direct use with an array of strings * const multiLineParagraph = block.paragraph.createBlock(["I'm a line", "I'm also a line!"]); * * // Usage with options object * const complexParagraph = block.paragraph.createBlock({ * rich_text: "Complex paragraph", * color: "red", * children: [ * // Child blocks would go here * ] * }); */ createBlock: (options) => { let rich_text, children, color; if (typeof options === "string" || Array.isArray(options)) { rich_text = options; children = []; color = "default"; } else { ({ rich_text = [], children = [], color = "default" } = options); } return { type: "paragraph", paragraph: { rich_text: rich_text === "" ? buildRichTextObj("") : enforceRichText(rich_text), color, ...children.length > 0 && { children } } }; } }, /** * Methods for PDF blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ pdf: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: false, /** * Creates a PDF block. * * @function * @param {string|Object} options - A string representing the PDF URL, a file upload ID, or an options object. * @param {string} options.url - The URL for the PDF. * @param {string} options.id - The ID of the file upload. * @param {string|string[]|Array<Object>} [options.caption=[]] - The caption as a string, an array of strings, or an array of rich text objects. * @returns {Object|null} A PDF block object compatible with Notion's API, or null if the URL/ID is invalid. * @example * // Use with a PDF URL * const externalPDF = block.pdf.createBlock("https://collegeinfogeek.com/wp-content/uploads/2015/01/10steps-reddit.pdf"); * * // Use with a file upload ID * const fileUploadPDF = block.pdf.createBlock("123e4567-e89b-12d3-a456-426614174000"); * * // Use with options object for external PDF * const externalPDF = block.pdf.createBlock({ * url: "https://collegeinfogeek.com/wp-content/uploads/2015/01/10steps-reddit.pdf", * caption: "The Reddit preview of the 10 Steps to Earning Awesome Grades book." * }); * * // Use with options object for file upload * const fileUploadPDF = block.pdf.createBlock({ * id: "123e4567-e89b-12d3-a456-426614174000", * caption: "The Reddit preview of the 10 Steps to Earning Awesome Grades book." * }); */ createBlock: (options) => { let url2, id, caption; if (typeof options === "string") { url2 = options; caption = []; } else { ({ url: url2, id, caption = [] } = options); } let urlOrId = url2 || id; const isValidPDF = validatePDFURL(urlOrId) || isValidUUID(urlOrId); const isFileUpload = isValidUUID(urlOrId); const isExternal = isValidURL(urlOrId); const pdfType = isFileUpload ? "file_upload" : isExternal ? "external" : "file"; if (!isValidPDF) { console.warn(`${urlOrId} is not a valid PDF URL or file upload ID.`); } return isValidPDF ? { type: "pdf", pdf: { type: pdfType, [pdfType]: { [pdfType === "file_upload" ? "id" : "url"]: urlOrId }, caption: enforceRichText(caption) } } : null; } }, /** * Methods for quote blocks. * * @namespace * @property {boolean} supports_children - Indicates if the block supports child blocks. */ quote: { /** * Indicates if the block supports child blocks. * @type {boolean} */ supports_children: true, /** * Creates a quote block. * * @function * @param {string|string[]|Object} options - A string, an array of strings, or an options object representing the quote content. * @param {string|string[]|Array<Object>} [options.rich_text=[]] - The content as a string, an array of strings, or an array of rich text objects. * @param {Array<Object>} [options.children=[]] - An array of child block objects. * @param {string} [options.color="default"] - Color for the text. * @returns {Object} A quote block object compatible with Notion's API. * @example * // Use with a string * const simpleQuote = block.quote.createBlock("Simple quote"); * * // Use with an array of strings * const mul