Token导航 LogoToken导航TokenDH.com
开发敏感数据github未标认证来源可访问许可证需确认审计通过

edit-embed编辑嵌入

Agent Skill

edit-embed 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

1,223

周安装

49

GitHub Stars

15

下载量

396
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:edit-embed(编辑嵌入)
来源仓库:https://github.com/stahura/domo-ai-vibe-rules
仓库路径:skills/edit-embed
安装命令:
npx skills add https://github.com/stahura/domo-ai-vibe-rules --skill edit-embed
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/stahura/domo-ai-vibe-rules --skill edit-embed

简介

用于 Domo 内容的嵌入式编辑,支持仪表板与报表的在线修改。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中集成身份认证与 JWT 授权流程。
  • 通过 iframe 渲染编辑界面,需服务器端生成带签名的访问令牌。
  • 仅限已配置 Domo Identity Broker 的环境使用,不支持只读嵌入。
  • edit-embed 属于开发类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

Domo Embedded Edit Experience

Let external users create, edit, save, and share Domo content (dashboards, cards, alerts, reports, data sources) through an embedded iframe. Uses the Domo Identity Broker with JWT auth — fundamentally different from read-only embeds.

For read-only embeds, see programmatic-filters. For client-side filtering, see jsapi-filters.

How It Works

  1. Your server authenticates the user and creates a JWT with identity, role, and routing attributes
  2. JWT is signed with a shared secret from Domo
  3. Server constructs edit URL: {IDP_URL}/jwt?token={jwt_token}
  4. Client renders URL directly as iframe src (no POST form needed)
  5. Identity Broker validates JWT, routes user to correct Domo instance by role

Key difference: read-only = OAuth → embed token → POST form. Edit = JWT → Identity Broker URL → iframe src.

Prerequisites

Work with your Domo CSM to set up the Identity Broker. Provide: your Domo instance URL, auth method (JWT), routing attribute key, and attribute-to-instance mappings.

You receive: Identity Broker URL, JWT signing secret (UUID), and attribute key config.

Required env vars: IDP_URL (Broker URL), JWT_SECRET (signing secret), KEY_ATTRIBUTE (routing attribute name).


The Domo Identity Broker

Authenticates users (validates JWT signature) and routes them to the correct Domo instance based on the mapping attribute. Supports SAML2, OIDC, JWT, OAuth2 — JWT is most common for embeds.

Instance Mapping

Each mapping attribute value corresponds to a Domo instance:

Attribute ValueDomo Instance
acme-corpacme.domo.com
globexglobex.domo.com
initechinitech.domo.com

Configured via your CSM (webform dataset or Excel). Comma-separated values route to multiple instances.


JWT Token Structure

Required Fields

FieldTypeDescription
substringThe user's identifier — typically their email address
expnumberExpiration time (EPOCH timestamp). Keep this short (5 minutes recommended)
jtistringUnique token identifier. Use a UUID v4 to prevent replay attacks
{KEY_ATTRIBUTE}string or string[]The routing attribute that maps the user to a Domo instance

Common Optional Fields

FieldTypeDescription
namestringDisplay name for the user in Domo
emailstringUser's email address
rolestringDomo role: Admin, Privileged, Editor, or Participant
employee_idstringEmployee identifier
titlestringJob title
departmentstringDepartment name
locationstringLocation
phonestringPhone number
localestringLocale preference
timezonestringTimezone preference
groupsstring[]Group assignments within Domo

Domo Roles

RoleCapabilities
AdminFull access — manage users, data, content, and settings
PrivilegedCreate/edit dashboards, cards, dataflows; manage data sources
EditorCreate/edit dashboards and cards; limited data source access
ParticipantView and interact with shared content only (default if omitted)

Most external users should be Editor or Participant.


Server-Side Implementation

Step 1: Create the JWT Token

Node.js / TypeScript:

import jwt from "jsonwebtoken";
import { v4 as uuidv4 } from "uuid";

function createEditToken(user: {
  username: string;
  email: string;
  domoRole?: string;
  mappingValue?: string | string[];
}) {
  const jwtBody: Record<string, unknown> = {
    sub: user.username,
    name: user.username,
    email: user.email,
    role: user.domoRole || "Participant",
    jti: uuidv4(),
  };

  // Add the routing attribute for instance mapping
  const keyAttribute = process.env.KEY_ATTRIBUTE;
  if (keyAttribute && user.mappingValue) {
    jwtBody[keyAttribute] = user.mappingValue;
  }

  return jwt.sign(jwtBody, process.env.JWT_SECRET!, {
    expiresIn: "5m",
    algorithm: "HS256",
  });
}

Python:

import jwt
import uuid
import time
import os

def create_edit_token(user):
    payload = {
        'sub': user['username'],
        'name': user['username'],
        'email': user['email'],
        'role': user.get('domo_role', 'Participant'),
        'jti': str(uuid.uuid4()),
        'exp': int(time.time()) + 300  # 5 minutes
    }

    key_attribute = os.environ.get('KEY_ATTRIBUTE')
    if key_attribute and user.get('mapping_value'):
        payload[key_attribute] = user['mapping_value']

    return jwt.encode(payload, os.environ['JWT_SECRET'], algorithm='HS256')

Step 2: Construct the Edit URL

const editUrl = `${process.env.IDP_URL}/jwt?token=${editToken}`;

Optionally deep-link to a specific page:

const editUrl = `${process.env.IDP_URL}/jwt?token=${editToken}&destination=/page/${pageId}`;

Step 3: Build the API Route

Next.js App Router:

// app/api/editembed/route.ts
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import jwt from "jsonwebtoken";
import { v4 as uuidv4 } from "uuid";

export async function POST(req: NextRequest) {
  try {
    const { embedID } = await req.json();

    // Authenticate the user against your own auth system
    const token = req.cookies.get("token")?.value;
    if (!token) {
      return NextResponse.json(
        { message: "Unauthorized: Please log in" },
        { status: 401 },
      );
    }

    const user = await verifyAndGetUser(token);
    if (!user) {
      return NextResponse.json({ message: "User not found" }, { status: 404 });
    }

    // Handle comma-separated mapping values
    let mappingValue = user.mappingValue;
    if (typeof mappingValue === "string" && mappingValue.includes(",")) {
      mappingValue = mappingValue.split(",").map((s: string) => s.trim());
    }

    // Build the JWT payload
    const jwtBody: Record<string, unknown> = {
      sub: user.username,
      name: user.username,
      role: user.domoRole || "Participant",
      email: user.email,
      jti: uuidv4(),
    };

    const keyAttr = process.env.KEY_ATTRIBUTE;
    if (keyAttr && mappingValue) {
      jwtBody[keyAttr] = mappingValue;
    }

    // Sign the token
    const editToken = jwt.sign(jwtBody, process.env.JWT_SECRET || "", {
      expiresIn: "5m",
    });

    // Return the Identity Broker URL
    const editUrl = `${process.env.IDP_URL}/jwt?token=${editToken}`;
    return NextResponse.json(editUrl);
  } catch (error) {
    console.error("Error in /api/editembed:", error);
    return NextResponse.json(
      { message: "Server error occurred" },
      { status: 500 },
    );
  }
}

Express example:

app.post("/api/editembed", authenticateUser, (req, res) => {
  const user = req.user;

  let mappingValue = user.mappingValue;
  if (typeof mappingValue === "string" && mappingValue.includes(",")) {
    mappingValue = mappingValue.split(",").map((s) => s.trim());
  }

  const jwtBody = {
    sub: user.username,
    name: user.username,
    role: user.domoRole || "Participant",
    email: user.email,
    jti: uuidv4(),
  };

  const keyAttr = process.env.KEY_ATTRIBUTE;
  if (keyAttr && mappingValue) {
    jwtBody[keyAttr] = mappingValue;
  }

  const editToken = jwt.sign(jwtBody, process.env.JWT_SECRET, {
    expiresIn: "5m",
  });

  const editUrl = `${process.env.IDP_URL}/jwt?token=${editToken}`;
  res.json(editUrl);
});

Step 4: Render in an Iframe

Edit embeds load directly via iframe src (no POST form like read-only embeds):

function EditEmbed({ editUrl }: { editUrl: string }) {
  return (
    <iframe
      src={editUrl}
      style={{ width: "100%", height: "100%", border: "none" }}
      allow="fullscreen"
    />
  );
}

Handling Read-Only vs Edit Mode

If your app supports both read-only and edit modes, your embed component needs to handle both flows:

function EmbedDashboard({ embedID }: { embedID: string }) {
  const [embedURL, setEmbedURL] = useState<string | null>(null);
  const [embedToken, setEmbedToken] = useState<string | null>(null);
  const isEditMode = embedID === "edit";

  useEffect(() => {
    const endpoint = isEditMode ? "/api/editembed" : "/api/getembedtoken";

    fetch(endpoint, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ embedID }),
      credentials: "include",
    })
      .then((res) => res.json())
      .then((data) => {
        if (isEditMode) {
          setEmbedURL(data); // Edit returns a direct URL string
          setEmbedToken(null);
        } else {
          setEmbedURL(data.embedUrl); // Read-only returns { embedUrl, embedToken }
          setEmbedToken(data.embedToken);
        }
      });
  }, [embedID, isEditMode]);

  // Edit mode: direct iframe src
  if (isEditMode && embedURL) {
    return (
      <iframe
        src={embedURL}
        style={{ width: "100%", height: "100%", border: "none" }}
      />
    );
  }

  // Read-only mode: POST form submission to iframe
  // (handle embedToken + form submission as in programmatic-filters skill)
}

User Management for Edit Embeds

Key User Properties

PropertyPurposeExample
domoRoleControls edit capabilities'Editor', 'Participant'
mappingValueRoutes user to correct Domo instance'acme-corp' or ['acme-corp', 'globex']
emailRequired for Domo user identity'user@example.com'

Multi-Instance Users

If a user needs access to multiple Domo instances, store their mappingValue as a comma-separated string or array:

// Single instance
user.mappingValue = "acme-corp";

// Multiple instances
user.mappingValue = "acme-corp, globex";
// or
user.mappingValue = ["acme-corp", "globex"];

When building the JWT, handle both formats:

let mappingValue = user.mappingValue;
if (typeof mappingValue === "string" && mappingValue.includes(",")) {
  mappingValue = mappingValue.split(",").map((s) => s.trim());
}

Deep Linking

const editUrl = `${IDP_URL}/jwt?token=${editToken}&destination=/page/${pageId}`;
const editUrl = `${IDP_URL}/jwt?token=${editToken}&destination=/kpicard/${cardId}`;

Gotchas and Best Practices

  • Token expiration: Keep JWTs short-lived (5 min recommended). Only used for initial auth — session persists after.
  • Signing algorithm: Use HS256. Domo expects this for the Identity Broker.
  • JTI uniqueness: Always UUID v4. Domo may reject reused JTI values (replay protection).
  • Mapping values: KEY_ATTRIBUTE name is whatever you agreed on with your CSM (customer, keyAttribute, tenant). Values must match Domo's instance mapping exactly.
  • Secret management: Never expose JWT_SECRET client-side. Use env vars or a secrets manager.
  • Security model: Read-only embeds scope to specific dashboards with filters. Edit embeds give a full Domo session per role — be conservative with role assignment.
  • Instance mapping changes: Use stable values (tenant IDs, not company names that might change).

Environment Variables Reference

VariableDescriptionExample
IDP_URLIdentity Broker URLhttps://yourcompany.identity.domo.com
JWT_SECRETShared signing secret (UUID format)aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee
KEY_ATTRIBUTEAttribute key for instance routingkeyAttribute, customer, tenant

TypeScript Type Definitions

type DomoRole = "Admin" | "Privileged" | "Editor" | "Participant";

interface EditEmbedUser {
  username: string;
  email: string;
  domoRole?: DomoRole;
  mappingValue?: string | string[];
}

interface EditJwtPayload {
  sub: string;
  name?: string;
  email?: string;
  role?: DomoRole;
  jti: string;
  exp?: number;
  [keyAttribute: string]: unknown; // dynamic routing attribute
}

Quick Reference

Read references/identity-broker.md for additional details on Identity Broker configuration and instance mapping management.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.75%
按下载量换算138

Claude

29.68%
按下载量换算118

Cursor

19.51%
按下载量换算77

Gemini CLI

9.12%
按下载量换算36

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills