Created
April 25, 2026 11:28
-
-
Save dvygolov/e26d9ee3b26ae1c10d2b6fbf0b216e1e to your computer and use it in GitHub Desktop.
This script helps to send a partner request for a Facebook Dataset (not usual pixel!) event if such requests are greyed in the UI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (function fbPixelPartnerRequestBootstrap() { | |
| "use strict"; | |
| const Config = { | |
| VERSION: "260423-ui", | |
| GRAPHQL_PATH: "/api/graphql/", | |
| MODAL_QUERY_DOC_ID: "24885284537836579", | |
| VALIDATION_QUERY_DOC_ID: "9794646500614064", | |
| MUTATION_DOC_ID: "26181988954765546", | |
| MODAL_QUERY_NAME: "BizKitSettingsAddPartnerToAssetByBusinessIDModalQuery", | |
| VALIDATION_QUERY_NAME: "BizKitSettingsAddPartnerToAssetByBusinessIDModalValidationQuery", | |
| MUTATION_NAME: "BizKitSettingsAddPartnerToAssetMutation", | |
| }; | |
| const state = { | |
| userId: "", | |
| fbDtsg: "", | |
| lsd: "", | |
| uiRoot: null, | |
| }; | |
| function log(level, message, details) { | |
| const prefix = `[FBPixelPartnerRequest ${Config.VERSION}]`; | |
| if (level === "error") { | |
| console.error(prefix, message, details ?? ""); | |
| return; | |
| } | |
| if (level === "warn") { | |
| console.warn(prefix, message, details ?? ""); | |
| return; | |
| } | |
| console.log(prefix, message, details ?? ""); | |
| } | |
| function escapeHtml(value) { | |
| return String(value ?? "") | |
| .replaceAll("&", "&") | |
| .replaceAll("<", "<") | |
| .replaceAll(">", ">") | |
| .replaceAll('"', """) | |
| .replaceAll("'", "'"); | |
| } | |
| function stripFacebookPrelude(text) { | |
| return typeof text === "string" && text.startsWith("for (;;);") ? text.slice(9) : text; | |
| } | |
| function getRuntimeModule(name) { | |
| try { | |
| if (typeof require === "function") { | |
| return require(name); | |
| } | |
| } catch (_error) { | |
| return null; | |
| } | |
| return null; | |
| } | |
| function getCurrentUserId() { | |
| const currentUser = getRuntimeModule("CurrentUserInitialData"); | |
| return String( | |
| currentUser?.USER_ID | |
| || currentUser?.ACCOUNT_ID | |
| || "", | |
| ); | |
| } | |
| function getFbDtsg() { | |
| return String( | |
| getRuntimeModule("DTSGInitialData")?.token | |
| || getRuntimeModule("DTSGInitData")?.token | |
| || "", | |
| ); | |
| } | |
| function getLsd() { | |
| return String(getRuntimeModule("LSD")?.token || ""); | |
| } | |
| function ensureSession() { | |
| state.userId = state.userId || getCurrentUserId(); | |
| state.fbDtsg = state.fbDtsg || getFbDtsg(); | |
| state.lsd = state.lsd || getLsd(); | |
| if (!state.userId || !state.fbDtsg || !state.lsd) { | |
| throw new Error("Could not extract runtime auth tokens. Run this on business.facebook.com while logged in."); | |
| } | |
| } | |
| function normalizeNumericId(value, label) { | |
| const normalized = String(value ?? "").trim().replace(/^act_/, ""); | |
| if (!/^\d+$/.test(normalized)) { | |
| throw new Error(`Invalid ${label}: ${value}`); | |
| } | |
| return normalized; | |
| } | |
| function getUrlParam(name) { | |
| return new URL(window.location.href).searchParams.get(name) || ""; | |
| } | |
| function getCurrentContext() { | |
| const businessId = normalizeNumericId(getUrlParam("business_id"), "business_id"); | |
| const assetId = normalizeNumericId(getUrlParam("selected_asset_id"), "selected_asset_id"); | |
| const assetType = String(getUrlParam("selected_asset_type") || ""); | |
| return { businessId, assetId, assetType }; | |
| } | |
| function isPixelAssetType(assetType) { | |
| return String(assetType || "").toLowerCase() === "pixel"; | |
| } | |
| function getPixelAssetWarning() { | |
| return [ | |
| "This script is intended for datasets, not plain pixels.", | |
| "Meta returns FAILURE for pixel assets under the new-business sharing gate and does not create a pending partner request.", | |
| "Open or create an events dataset instead, then run the tool there.", | |
| ].join(" "); | |
| } | |
| async function graphqlRequest(options) { | |
| ensureSession(); | |
| const { | |
| friendlyName, | |
| docId, | |
| variables, | |
| businessId, | |
| } = options; | |
| const normalizedBusinessId = normalizeNumericId(businessId, "businessId"); | |
| const payload = new URLSearchParams(); | |
| payload.set("av", state.userId); | |
| payload.set("__aaid", "0"); | |
| payload.set("__bid", normalizedBusinessId); | |
| payload.set("__user", state.userId); | |
| payload.set("__a", "1"); | |
| payload.set("fb_dtsg", state.fbDtsg); | |
| payload.set("lsd", state.lsd); | |
| payload.set("fb_api_caller_class", "RelayModern"); | |
| payload.set("fb_api_req_friendly_name", friendlyName); | |
| payload.set("server_timestamps", "true"); | |
| payload.set("variables", JSON.stringify(variables || {})); | |
| payload.set("doc_id", docId); | |
| const response = await fetch(Config.GRAPHQL_PATH, { | |
| method: "POST", | |
| credentials: "include", | |
| headers: { | |
| "content-type": "application/x-www-form-urlencoded", | |
| }, | |
| body: payload, | |
| }); | |
| const text = stripFacebookPrelude(await response.text()); | |
| let json; | |
| try { | |
| json = text ? JSON.parse(text) : {}; | |
| } catch (_error) { | |
| throw new Error(`Failed to parse GraphQL response: ${text.slice(0, 400)}`); | |
| } | |
| if (!response.ok || json.error || json.errors?.length) { | |
| throw new Error(JSON.stringify(json.error || json.errors || { status: response.status, text }, null, 2)); | |
| } | |
| return json; | |
| } | |
| async function loadModalConfig(context = {}) { | |
| const resolved = { | |
| ...getCurrentContext(), | |
| ...context, | |
| }; | |
| const businessId = normalizeNumericId(resolved.businessId, "businessId"); | |
| const assetId = normalizeNumericId(resolved.assetId, "assetId"); | |
| const json = await graphqlRequest({ | |
| friendlyName: Config.MODAL_QUERY_NAME, | |
| docId: Config.MODAL_QUERY_DOC_ID, | |
| businessId, | |
| variables: { | |
| assetID: assetId, | |
| businessID: businessId, | |
| }, | |
| }); | |
| const asset = json?.data?.asset; | |
| const configs = Array.isArray(asset?.available_permission_tasks_ui_configs) | |
| ? asset.available_permission_tasks_ui_configs | |
| : []; | |
| return { | |
| business: json?.data?.business || null, | |
| asset, | |
| configs, | |
| context: { | |
| businessId, | |
| assetId, | |
| assetType: resolved.assetType || asset?.business_asset_type || "", | |
| }, | |
| }; | |
| } | |
| async function validatePartner(options) { | |
| const businessId = normalizeNumericId(options?.businessId, "businessId"); | |
| const assetId = normalizeNumericId(options?.assetId, "assetId"); | |
| const partnerBusinessId = normalizeNumericId(options?.partnerBusinessId, "partnerBusinessId"); | |
| const json = await graphqlRequest({ | |
| friendlyName: Config.VALIDATION_QUERY_NAME, | |
| docId: Config.VALIDATION_QUERY_DOC_ID, | |
| businessId, | |
| variables: { | |
| assetID: assetId, | |
| businessID: businessId, | |
| partnerBusinessID: partnerBusinessId, | |
| }, | |
| }); | |
| const isValid = Boolean(json?.data?.business?.business_partnership_validation); | |
| return { | |
| ok: isValid, | |
| raw: json, | |
| }; | |
| } | |
| function dedupe(values) { | |
| return [...new Set((values || []).filter(Boolean).map((value) => String(value)))]; | |
| } | |
| function resolveTaskIds(mode, configs) { | |
| const normalizedMode = String(mode || "partial").trim().toLowerCase(); | |
| const list = Array.isArray(configs) ? configs : []; | |
| if (normalizedMode === "partial") { | |
| const match = list.find((item) => | |
| item?.task_permission_type === "PARTIAL_ACCESS_TASK" | |
| || item?.task_name === "ANALYZE" | |
| || /use events dataset/i.test(String(item?.task_label || "")) | |
| ); | |
| if (!match?.task_id) { | |
| throw new Error("Could not resolve partial-access task for this asset."); | |
| } | |
| return [String(match.task_id)]; | |
| } | |
| if (normalizedMode === "full") { | |
| const match = list.find((item) => | |
| item?.task_permission_type === "FULL_CONTROL_TASK" | |
| || item?.task_name === "EDIT" | |
| || /manage events dataset/i.test(String(item?.task_label || "")) | |
| ); | |
| if (!match?.task_id) { | |
| throw new Error("Could not resolve full-control task for this asset."); | |
| } | |
| return dedupe([ | |
| match.task_id, | |
| ...(match.hard_implied_task_ids || []), | |
| ...(match.implied_task_ids || []), | |
| ]); | |
| } | |
| throw new Error(`Unsupported mode: ${mode}. Use "partial" or "full".`); | |
| } | |
| async function addPartner(options = {}) { | |
| const current = getCurrentContext(); | |
| const businessId = normalizeNumericId(options.businessId || current.businessId, "businessId"); | |
| const assetId = normalizeNumericId(options.assetId || current.assetId, "assetId"); | |
| const partnerBusinessId = normalizeNumericId(options.partnerBusinessId, "partnerBusinessId"); | |
| const mode = String(options.mode || "partial").toLowerCase(); | |
| const assetType = options.assetType || current.assetType; | |
| if (isPixelAssetType(assetType)) { | |
| throw new Error(getPixelAssetWarning()); | |
| } | |
| const modal = await loadModalConfig({ businessId, assetId, assetType }); | |
| const taskIds = Array.isArray(options.taskIds) && options.taskIds.length | |
| ? dedupe(options.taskIds.map((value) => normalizeNumericId(value, "taskId"))) | |
| : resolveTaskIds(mode, modal.configs); | |
| const validation = await validatePartner({ | |
| businessId, | |
| assetId, | |
| partnerBusinessId, | |
| }); | |
| if (!validation.ok) { | |
| throw new Error(`Partner validation failed for business ${partnerBusinessId}.`); | |
| } | |
| const json = await graphqlRequest({ | |
| friendlyName: Config.MUTATION_NAME, | |
| docId: Config.MUTATION_DOC_ID, | |
| businessId, | |
| variables: { | |
| businessID: businessId, | |
| assetID: assetId, | |
| surfaceParams: { | |
| entry_point: "BIZWEB_SETTINGS_ASSETS_VIEW_DETAILS_HEADER", | |
| flow_source: "BIZ_WEB", | |
| tab: "EVENTS_DATASET_AND_PIXEL", | |
| }, | |
| toBusinessID: partnerBusinessId, | |
| taskIDs: taskIds, | |
| shouldFetchPartnerName: false, | |
| }, | |
| }); | |
| const result = { | |
| businessId, | |
| assetId, | |
| assetType: modal.context.assetType, | |
| assetName: modal.asset?.name || modal.asset?.business_object_name || "", | |
| partnerBusinessId, | |
| mode, | |
| taskIds, | |
| validationOk: true, | |
| raw: json, | |
| }; | |
| log("info", `Partner request sent for asset ${assetId} to BM ${partnerBusinessId}.`, result); | |
| return result; | |
| } | |
| function extractMutationSummary(result) { | |
| const raw = result?.raw || {}; | |
| const connection = raw?.data?.business_settings_add_partner_to_asset_connection || null; | |
| const mutation = | |
| raw?.data?.xfb_business_settings_add_partner_to_asset | |
| || raw?.data?.business_settings_add_partner_to_asset | |
| || raw?.data?.add_partner_to_asset | |
| || connection?.results | |
| || null; | |
| const resultType = | |
| mutation?.result_type | |
| || mutation?.resultType | |
| || connection?.results?.result_type | |
| || raw?.data?.result_type | |
| || ""; | |
| const policy = | |
| mutation?.policy_result | |
| || mutation?.policyResult | |
| || mutation?.can_viewer_assign_to_agency_business_result | |
| || mutation?.can_viewer_share_asset_result | |
| || connection?.business_asset?.can_viewer_assign_to_agency_business_result | |
| || connection?.proxiable_object?.can_viewer_assign_to_agency_business_result | |
| || null; | |
| const reasonChain = Array.isArray(policy?.reason_chain) | |
| ? policy.reason_chain.map((item) => item?.name || item).filter(Boolean) | |
| : []; | |
| return { | |
| resultType, | |
| didPassPolicy: typeof policy?.did_pass_policy === "boolean" ? policy.did_pass_policy : null, | |
| reasonChain, | |
| exceptionDescription: | |
| policy?.exception?.description | |
| || policy?.exception?.message | |
| || policy?.exception_description | |
| || "", | |
| }; | |
| } | |
| function setUiStatus(type, message, details) { | |
| const root = state.uiRoot; | |
| if (!root) return; | |
| const status = root.querySelector("[data-fbppr-status]"); | |
| if (!status) return; | |
| const colors = { | |
| info: ["#eef6ff", "#184f8b"], | |
| success: ["#edf9f1", "#17663a"], | |
| warn: ["#fff8e5", "#795000"], | |
| error: ["#fff0f0", "#8a1f1f"], | |
| }; | |
| const [background, color] = colors[type] || colors.info; | |
| status.style.background = background; | |
| status.style.color = color; | |
| status.innerHTML = ` | |
| <div style="font-weight:700;margin-bottom:4px">${escapeHtml(message)}</div> | |
| ${details ? `<pre style="white-space:pre-wrap;margin:0;font:12px/1.35 ui-monospace,SFMono-Regular,Consolas,monospace">${escapeHtml(details)}</pre>` : ""} | |
| `; | |
| } | |
| function setUiBusy(isBusy) { | |
| const root = state.uiRoot; | |
| if (!root) return; | |
| const submit = root.querySelector("[data-fbppr-submit]"); | |
| const close = root.querySelector("[data-fbppr-close]"); | |
| if (submit) { | |
| submit.disabled = Boolean(isBusy); | |
| submit.textContent = isBusy ? "Sending..." : "Send partner request"; | |
| } | |
| if (close) { | |
| close.disabled = Boolean(isBusy); | |
| } | |
| } | |
| function setSubmitBlocked(isBlocked) { | |
| const root = state.uiRoot; | |
| if (!root) return; | |
| const submit = root.querySelector("[data-fbppr-submit]"); | |
| if (!submit) return; | |
| submit.disabled = Boolean(isBlocked); | |
| submit.style.opacity = isBlocked ? ".55" : "1"; | |
| submit.style.cursor = isBlocked ? "not-allowed" : "pointer"; | |
| } | |
| function removeExistingUi() { | |
| const existing = document.getElementById("fb-pixel-partner-request-ui"); | |
| if (existing) existing.remove(); | |
| state.uiRoot = null; | |
| } | |
| async function refreshUiContext() { | |
| const root = state.uiRoot; | |
| if (!root) return null; | |
| try { | |
| const context = getCurrentContext(); | |
| root.querySelector("[data-fbppr-asset-id]").textContent = context.assetId; | |
| if (isPixelAssetType(context.assetType)) { | |
| setSubmitBlocked(true); | |
| setUiStatus("warn", "Pixel asset detected.", getPixelAssetWarning()); | |
| return null; | |
| } | |
| setSubmitBlocked(false); | |
| const modal = await loadModalConfig(context); | |
| setUiStatus("info", "Ready.", "Enter target BM ID and send the partner request."); | |
| return modal; | |
| } catch (error) { | |
| setSubmitBlocked(true); | |
| setUiStatus("error", "Could not read current dataset context.", error?.message || String(error)); | |
| return null; | |
| } | |
| } | |
| function showUI() { | |
| removeExistingUi(); | |
| const root = document.createElement("div"); | |
| root.id = "fb-pixel-partner-request-ui"; | |
| root.style.cssText = [ | |
| "position:fixed", | |
| "right:24px", | |
| "bottom:24px", | |
| "z-index:2147483647", | |
| "width:420px", | |
| "max-width:calc(100vw - 32px)", | |
| "background:#f7f2e8", | |
| "color:#20262d", | |
| "border:1px solid #d6cab7", | |
| "border-radius:18px", | |
| "box-shadow:0 24px 80px rgba(38,31,22,.28)", | |
| "font:14px/1.4 Segoe UI,Arial,sans-serif", | |
| "overflow:hidden", | |
| ].join(";"); | |
| root.innerHTML = ` | |
| <div style="padding:16px 18px;background:linear-gradient(135deg,#233429,#536d46);color:#fff"> | |
| <div style="display:flex;align-items:start;justify-content:space-between;gap:12px"> | |
| <div> | |
| <div style="font-size:16px;font-weight:800;letter-spacing:.2px">Pixel Partner Request</div> | |
| <div style="opacity:.82;font-size:12px;margin-top:2px">Send dataset/pixel access request to another BM</div> | |
| <div style="opacity:.78;font-size:11px;margin-top:4px"> | |
| by <a href="https://yellowweb.top" target="_blank" rel="noopener noreferrer" style="color:#fff;text-decoration:underline">Yellow Web</a> | |
| </div> | |
| </div> | |
| <button data-fbppr-close type="button" style="border:0;background:rgba(255,255,255,.14);color:#fff;border-radius:999px;width:30px;height:30px;cursor:pointer;font-size:18px;line-height:1">×</button> | |
| </div> | |
| </div> | |
| <div style="padding:16px 18px"> | |
| <div style="display:grid;grid-template-columns:80px 1fr;gap:5px 10px;font-size:12px;margin-bottom:14px;color:#47515b"> | |
| <div>Asset ID</div><div data-fbppr-asset-id style="font-family:ui-monospace,SFMono-Regular,Consolas,monospace">...</div> | |
| </div> | |
| <label style="display:block;font-weight:700;margin-bottom:6px">Target BM ID</label> | |
| <input data-fbppr-partner-id inputmode="numeric" placeholder="928719119582773" style="box-sizing:border-box;width:100%;border:1px solid #c8bcaa;border-radius:12px;padding:11px 12px;font:15px ui-monospace,SFMono-Regular,Consolas,monospace;background:#fffaf1;color:#1d262f;outline:none" /> | |
| <div style="display:flex;gap:10px;margin:14px 0 12px"> | |
| <label style="flex:1;border:1px solid #c8bcaa;border-radius:12px;padding:10px;background:#fffaf1;cursor:pointer"> | |
| <input type="radio" name="fbppr-mode" value="partial" checked /> | |
| <span style="font-weight:700">Partial</span> | |
| <div style="font-size:12px;color:#65717c;margin-top:2px">Use events dataset</div> | |
| </label> | |
| <label style="flex:1;border:1px solid #c8bcaa;border-radius:12px;padding:10px;background:#fffaf1;cursor:pointer"> | |
| <input type="radio" name="fbppr-mode" value="full" /> | |
| <span style="font-weight:700">Full</span> | |
| <div style="font-size:12px;color:#65717c;margin-top:2px">Manage events dataset</div> | |
| </label> | |
| </div> | |
| <div style="display:flex;gap:10px;margin-top:14px"> | |
| <button data-fbppr-submit type="button" style="flex:1;border:0;border-radius:12px;padding:11px 14px;background:#2c6d55;color:#fff;font-weight:800;cursor:pointer">Send partner request</button> | |
| </div> | |
| <div data-fbppr-status style="margin-top:14px;border-radius:12px;padding:11px 12px;background:#eef6ff;color:#184f8b;font-size:12px"> | |
| <div style="font-weight:700">Loading context...</div> | |
| </div> | |
| <a data-fbppr-bookmark href="#" style="display:block;text-align:center;margin-top:10px;font-size:12px;color:#385b9f;text-decoration:underline">Copy as bookmark</a> | |
| </div> | |
| `; | |
| document.body.appendChild(root); | |
| state.uiRoot = root; | |
| const savedPartnerId = localStorage.getItem("FBPixelPartnerRequest.partnerBusinessId") || ""; | |
| root.querySelector("[data-fbppr-partner-id]").value = savedPartnerId; | |
| root.querySelector("[data-fbppr-close]").addEventListener("click", hideUI); | |
| root.querySelector("[data-fbppr-bookmark]").addEventListener("click", (event) => { | |
| event.preventDefault(); | |
| copyAsBookmarklet(); | |
| }); | |
| root.querySelector("[data-fbppr-submit]").addEventListener("click", async () => { | |
| const partnerBusinessId = root.querySelector("[data-fbppr-partner-id]").value.trim(); | |
| const mode = root.querySelector("input[name='fbppr-mode']:checked")?.value || "partial"; | |
| if (!partnerBusinessId) { | |
| setUiStatus("warn", "Target BM ID is required."); | |
| return; | |
| } | |
| const context = getCurrentContext(); | |
| if (isPixelAssetType(context.assetType)) { | |
| setSubmitBlocked(true); | |
| setUiStatus("warn", "Pixel asset detected.", getPixelAssetWarning()); | |
| return; | |
| } | |
| try { | |
| setUiBusy(true); | |
| setUiStatus("info", "Sending request...", `Target BM: ${partnerBusinessId}\nMode: ${mode}`); | |
| localStorage.setItem("FBPixelPartnerRequest.partnerBusinessId", partnerBusinessId); | |
| const result = await addPartner({ | |
| businessId: context.businessId, | |
| assetId: context.assetId, | |
| assetType: context.assetType, | |
| partnerBusinessId, | |
| mode, | |
| }); | |
| const summary = extractMutationSummary(result); | |
| const details = [ | |
| `Source BM: ${result.businessId}`, | |
| `Asset: ${result.assetName || result.assetId}`, | |
| `Target BM: ${result.partnerBusinessId}`, | |
| `Mode: ${result.mode}`, | |
| `Task IDs: ${result.taskIds.join(", ")}`, | |
| summary.resultType ? `Result: ${summary.resultType}` : "", | |
| summary.didPassPolicy === null ? "" : `Policy passed: ${summary.didPassPolicy}`, | |
| summary.reasonChain.length ? `Policy reasons: ${summary.reasonChain.join(" > ")}` : "", | |
| summary.exceptionDescription ? `Policy exception: ${summary.exceptionDescription}` : "", | |
| ].filter(Boolean).join("\n"); | |
| if (summary.resultType === "FAILURE") { | |
| setUiStatus("error", "Partner request failed.", details); | |
| } else { | |
| setUiStatus("success", "Partner request sent.", details); | |
| } | |
| } catch (error) { | |
| setUiStatus("error", "Partner request failed.", error?.message || String(error)); | |
| } finally { | |
| setUiBusy(false); | |
| } | |
| }); | |
| refreshUiContext(); | |
| return root; | |
| } | |
| function hideUI() { | |
| removeExistingUi(); | |
| } | |
| function copyTextToClipboard(text) { | |
| if (navigator.clipboard?.writeText) { | |
| return navigator.clipboard.writeText(text); | |
| } | |
| const textarea = document.createElement("textarea"); | |
| textarea.value = text; | |
| textarea.style.position = "fixed"; | |
| textarea.style.left = "-9999px"; | |
| textarea.style.top = "-9999px"; | |
| document.body.appendChild(textarea); | |
| textarea.select(); | |
| document.execCommand("copy"); | |
| textarea.remove(); | |
| return Promise.resolve(); | |
| } | |
| async function copyAsBookmarklet() { | |
| try { | |
| const raw = `(${fbPixelPartnerRequestBootstrap.toString()})();`; | |
| const base64 = btoa(unescape(encodeURIComponent(raw))); | |
| const bookmarklet = `javascript:eval(decodeURIComponent(escape(atob("${base64}"))));`; | |
| await copyTextToClipboard(bookmarklet); | |
| setUiStatus("success", "Bookmarklet copied.", "Create a browser bookmark and paste the copied code as its URL."); | |
| } catch (error) { | |
| setUiStatus("error", "Failed to copy bookmarklet.", error?.message || String(error)); | |
| } | |
| } | |
| async function addPartnerFromPrompt() { | |
| const context = getCurrentContext(); | |
| const partnerBusinessId = window.prompt("Partner business ID", ""); | |
| if (partnerBusinessId === null) { | |
| throw new Error("Cancelled by user."); | |
| } | |
| const modeRaw = window.prompt("Access mode: partial or full", "partial"); | |
| if (modeRaw === null) { | |
| throw new Error("Cancelled by user."); | |
| } | |
| const result = await addPartner({ | |
| businessId: context.businessId, | |
| assetId: context.assetId, | |
| assetType: context.assetType, | |
| partnerBusinessId, | |
| mode: modeRaw, | |
| }); | |
| console.table({ | |
| businessId: result.businessId, | |
| assetId: result.assetId, | |
| partnerBusinessId: result.partnerBusinessId, | |
| mode: result.mode, | |
| taskIds: result.taskIds.join(", "), | |
| }); | |
| return result; | |
| } | |
| function showCurrentContext() { | |
| const context = getCurrentContext(); | |
| console.table(context); | |
| return context; | |
| } | |
| function help() { | |
| const lines = [ | |
| "Run this on business.facebook.com > Settings > Datasets & pixels with the target dataset open in the details panel.", | |
| "The current URL must contain selected_asset_id and business_id.", | |
| "", | |
| "Examples:", | |
| "FBPixelPartnerRequest.help()", | |
| "FBPixelPartnerRequest.showCurrentContext()", | |
| "FBPixelPartnerRequest.showUI()", | |
| "await FBPixelPartnerRequest.loadModalConfig()", | |
| "await FBPixelPartnerRequest.addPartnerFromPrompt()", | |
| "await FBPixelPartnerRequest.addPartner({ partnerBusinessId: '928719119582773', mode: 'partial' })", | |
| "await FBPixelPartnerRequest.addPartner({ businessId: '1408911316476255', assetId: '388444524197528', partnerBusinessId: '928719119582773', mode: 'full' })", | |
| "", | |
| "Modes:", | |
| "- partial: uses the PARTIAL_ACCESS task from the live modal config", | |
| "- full: uses the FULL_CONTROL task and its implied task IDs from the live modal config", | |
| ]; | |
| console.log(lines.join("\n")); | |
| } | |
| const api = { | |
| version: Config.VERSION, | |
| help, | |
| showCurrentContext, | |
| showUI, | |
| hideUI, | |
| copyAsBookmarklet, | |
| loadModalConfig, | |
| validatePartner, | |
| addPartner, | |
| addPartnerFromPrompt, | |
| }; | |
| window.FBPixelPartnerRequest = api; | |
| showUI(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment